### Loading Packages###

renv::restore()

packages <- c(
  "tidyverse",
  "sf",
  "patchwork",
  "stringr",
  "eulerr",
  "indicspecies",
  "cluster",
  "vegan",
  "chisq.posthoc.test",
  "taxize",
  "Polychrome",
  "pals",
  "spocc",
  "mregions",
  "rgbif",
  "mapview",
  "ggbeeswarm",
  "ggh4x",
  "chunkhooks",
  "devtools",
  "grid",
  "styler",
  "phyloseq",
  "ggtree",
  "ggtreeExtra",
  "ampvis2",
  "pdftools",
  "gt",
  "gtExtras"
)

invisible(lapply(packages, library, character.only = TRUE))

hook_figure_unit()
### Core Functions###
# Collection of functions used across analyses

# Function that removes NCBI Taxonomy IDs from the end of taxonomic names (as in the Anacapa Pipeline output)
remove_NCBInums <- function(list) {
  list <- sub("_[^_]+$", "", list)
  return(list)
}

# Function that converts an ampvis2 object to a phyloseq object
# Can be used either on an existing ampvis2 object (abund, tax, md = NULL) or separate abund, tax, and metadata data frames (ampvis = NULL)
amp_to_phyloseq <- function(ampvis, abund, tax, md) {
  if (!is.null(ampvis)) {
    physeq <- phyloseq(
      otu_table(as.matrix(ampvis$abund), taxa_are_rows = TRUE),
      tax_table(as.matrix(ampvis$tax)),
      sample_data(ampvis$metadata)
    )
  } else if (is.null(md)) {
    physeq <- phyloseq(
      otu_table(as.matrix(abund), taxa_are_rows = TRUE),
      tax_table(as.matrix(tax))
    )
  } else {
    physeq <- phyloseq(
      otu_table(as.matrix(abund), taxa_are_rows = TRUE),
      tax_table(as.matrix(tax)),
      sample_data(md)
    )
  }
  return(physeq)
}

# Function that saves .png and .pdf versions of a given figure
save_pdf_png <- function(plot, path, w, h, u, bg, dpi) {
  for (x in c("pdf", "png")) {
    ggsave(
      plot = plot,
      filename = paste0(path, x),
      device = x,
      bg = bg,
      width = w,
      height = h,
      units = u,
      dpi = dpi
    )
  }
}

Materials and Methods

2.1 Detailed Protocols

To improve reproducibility (e.g. Dickie et al., 2018; Shea et al., 2023), enable open data science (e.g. Fredston and Lowndes, 2024), and aid in the initiation of new eDNA biomonitoring projects, we have published detailed, step-by-step protocols for many of the methods described, including specific materials used, photographs, and additional methodological notes not possible to include here. See Shea (2023) for sample collection and filtering, Shea (2023) for DNA extractions, Shea (2023) for PCR amplification, and Shea (2023) for shipping samples. Additionally, we have published all data and code for replicating our analyses via Dryad, including FASTQ files, our modified Anacapa Container and scripts for bioinformatics, unprocessed and processed datasets, and an R Markdown file that reproduces all methods & results detailed here (Dryad citation).

2.2 Sampling Site

To better understand spatial and temporal differences in eDNA signals in a complex coastal environment, we sought a rocky intertidal field location that had consistent, large, accessible tide pools that were fully isolated from one another at some low tides but interconnected during other parts of their exposure period. We selected the intertidal at Pillar Point, a headlands promontory to the west of Pillar Point Harbor in San Mateo County, California, USA. Pillar Point is a popular recreational intertidal site that is directly adjacent to the Pillar Point State Marine Conservation Area (no specific use scientific collection permit required).

Within Pillar Point, we sampled at three discrete locations: two individual tide pools with a range of physical connectivity (Tide Pool 1, S1: 37.495342°, -122.498731°; Tide Pool 2, S2: 37.495000°, -122.498947°) and an equidistant location (Nearshore, N: 37.4952833°, -122.4992056°) where there was well-mixed offshore water for the duration of the tidal cycle (Figure 2; not produced in R). Each site was approximately 40 meters from all other sites. Tide Pool 1 and Tide Pool 2 are fully isolated at tidal heights of around 0 m (mean low low water, MLLW) or lower, and substantially connected at around 0.25 m or higher. On the day we sampled, this meant water actively flowed between the locations at the start (11:30 PST) and end (17:00 PST) of the sampling period, but that the sites were disconnected at low tide in the middle of the sampling period.

2.3 Sample Collection & Filtration

We collected 1 L surface samples from each location every 30 minutes for the duration of time the rocky intertidal was exposed on 28 January 2022, using single-use enteral feeding pouches (Covidien, Dublin, Ireland). Sampling commenced at 11:30 PST; the exact times of sample collection, in relation to the tide, are shown in Figure 3. Following the approach used by Gold et al. (2021b), we attached a sterile 0.22 \(\mu\)m pore size Sterivex cartridge (MilliporeSigma, Burlington, MA, USA) to the tubing of each feeding pouch, allowing samples to be immediately gravity filtered in the field. While gravity filtering (1-2 hours per sample), samples were shaded with an awning to prevent any degradation by sunlight (Andruszkiewicz et al., 2017).

### Figure 3###
# Produce the top portion of Figure 3 from tide data

# Read Pillar Point NOAA/NOS/CO-OPs Tide Chart data file
Tides <- read.table("Data/28-Jan-2022-TideChart.txt", header = TRUE, sep = "", dec = ".", skip = 13)

# Convert date format in table using lubridate
Tides$datetime <- lubridate::ymd_hm(paste(Tides$Date, Tides$Time), tz = "US/Pacific")

# Set bounds of sampling period to highlight
xmin <- Tides$datetime[47]
xmax <- Tides$datetime[69]
ymin <- -.5
ymax <- .5

box_color <- "#808080"

# Create plot of full tidal cycle with sampling period highlighted
p1 <- ggplot(data = Tides, aes(x = datetime, y = Pred, group = 1)) +
  annotate("rect", xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = box_color) +
  geom_line() +
  coord_cartesian(xlim = c(Tides$datetime[1], Tides$datetime[96])) +
  theme_classic(base_size = 12) +
  theme(
    panel.background = element_rect(fill = "transparent", colour = NA_character_),
    # necessary to avoid drawing panel outline
    plot.background = element_rect(fill = "transparent", colour = NA_character_),
    # necessary to avoid drawing plot outline
    axis.text.x = element_text(color = "black"),
    axis.ticks = element_line(color = "black"),
    axis.text.y = element_text(color = "black"),
    panel.border = element_rect(colour = "black", fill = NA, linewidth = 1)
  ) +
  xlab("Time (PST)") +
  ylab("MLLW Tide Prediction (m)") +
  scale_x_datetime(date_breaks = "2 hour", date_labels = "%H:00", expand = c(0, 0), position = "top")

# Create plot of just sampling period
p2 <- ggplot(data = Tides, aes(x = datetime, y = Pred, group = 1)) +
  geom_line() +
  coord_cartesian(xlim = c(xmin, xmax), ylim = c(ymin, ymax)) +
  theme_classic(base_size = 12) +
  theme(
    panel.background = element_rect(fill = box_color),
    plot.background = element_rect(fill = "transparent", colour = NA_character_),
    axis.text.x = element_text(color = "black"),
    axis.ticks = element_line(color = "black"),
    axis.text.y = element_text(color = "black"),
    panel.border = element_rect(colour = "black", fill = NA, linewidth = 1)
  ) +
  theme(axis.title.x = element_blank()) +
  ylab("MLLW Tide Prediction (m)") +
  scale_x_datetime(date_breaks = "30 min", date_labels = "%H:%M", expand = c(0, 0)) +
  theme(plot.margin = margin(b = 0))

# Stitch plots together using patchwork
p_patch <- p1 / (p2 & theme(plot.margin = margin(0, 0, 0, 0, "pt"))) & ylab(NULL) & theme(plot.background = element_rect(fill = "transparent", colour = NA_character_))

# Use the tag label as a y-axis label
p_patch <- wrap_elements(p_patch) +
  labs(tag = "MLLW Tide Prediction (m)") +
  theme(
    plot.tag = element_text(size = rel(1.2), angle = 90),
    plot.tag.position = "left",
    plot.background = element_rect(fill = "transparent", colour = NA_character_)
  )


if (!dir.exists("Figures")) {
  dir.create("Figures")
}
path <- "Figures/Figure3."
save_pdf_png(plot = p_patch, path = path, w = 169, h = 90, u = "mm", bg = "transparent", dpi = 600)
First component of Figure 3 (second section added once data has been loaded
First component of Figure 3 (second section added once data has been loaded

At three time points (see full Figure 3, finalized below) at the beginning and end of the sampling period as well as at low tide (at 14:00 PST), we collected triplicate 1 L samples from each location as biological replicates. At the beginning and end of the sampling period, we also filtered 1 L MilliQ water via the procedure described above to serve as negative field controls. Additionally, using an Orion Model 1230 meter (Orion Research Inc., Beverly, MA, USA), we recorded temperature and salinity in each location directly after samples were collected.

Once finished filtering, Sterivex cartridges were dried by pushing air through them using a sterile 3 mL syringe, capped, placed in sterile Whirl-Pak bags (Whirl-Pak, Madison, WI, USA). Then, samples were stored in a cooler on ice until transported back to the laboratory at the end of the sampling period. Samples were transferred to a -20°C freezer for up to 18 days, at which time they were processed to extract nucleic acids from the captured materials.

2.4 DNA Extraction & Library Preparation

Within 18 days of collection, we extracted DNA from the Sterivex cartridge using the DNeasy Blood and Tissue Kit (Qiagen, Germantown, MD, USA) and the modifications described in Spens et al. (2017). In short, we incubated the filter cartridge overnight with proteinase K and ATL. Then, we extracted the liquid from the cartridge with a syringe and mixed it with equal volumes of AL buffer and 0°C ethanol before proceeding with the manufacturer’s extraction protocol. One negative extraction control (DNA-grade water in place of a sample) was included in each of four batches of extractions. Extracted samples to be PCR amplified were stored at -20°C for up to 6 months.

We PCR amplified the extracted DNA in triplicate within 6 months of storage, using the mlCOIintF/ jgHCO2198 primer set targeting a 313 bp fragment of the mitochondrial COI region optimized by Leray et al. (2013) (Forward: GGWACWGGWTGAACWGTWTAYCCYCC; Reverse: TAIACYTCIGGRTGICCRAARAAYCA) with Nextera modifications. Following Curd et al. (2019), we used a 25 \(\mu\)l PCR reaction mixture consisting of 12.5 \(\mu\)l of Qiagen Multiplex Mix (Qiagen, Germantown, MD, USA), 2.5 \(\mu\)l each of the forward and reverse primers at 2 \(\mu\)M (Integrated DNA Technologies, Inc., Coralville, IA, USA), 6.5 \(\mu\)l of PCR-grade water, and 1 \(\mu\)l of undiluted DNA template. The PCR thermocycling touchdown profile began with an initial denaturation at 95° for 15 minutes to activate the DNA polymerase, followed by 13 cycles of denaturation (94° for 30 seconds), annealing (starting at 69.5° for 30 seconds, with the temperature decreased by 1.5° each cycle), and extension (72° for 1 minute). Then, an additional 35 cycles were run with the same denaturation and extension steps as above with an annealing temperature of 50°, followed by a final extension at 72° for 10 minutes. PCR reactions were prepared in a designated DNA-free hood until the template was added.

PCR amplification was conducted in two batches; in each batch, we included one no-template negative PCR control (DNA-grade water used as template). Additionally, we extracted DNA from tissue from five organisms across a range of phyla we expected to amplify with the mlCOIintF/ jgHCO2198 primers, but not expected to be present at Pillar Point in particular (Mytilus edulis, Mizuhopecten yessoensis, Xiphias gladius, Mercenaria mercenaria, Lutjanus campechanus) using the standard tissue extraction protocol detailed in the DNeasy Blood and Tissue Kit (Qiagen, Germantown, MD, USA). These tissues were obtained from a local grocery store and it was assumed that they were labeled correctly, although previous work has indicated mislabeling in seafood stores can occur (e.g. Willette et al., 2017). Extracts from the 5 tissue samples were combined in equimolar amounts to form a mock community used as a positive PCR control in each batch. Triplicate PCR amplicons from both samples and controls were not subsequently pooled, but were carried through the remaining library preparation and sequencing steps as technical replicates. We electrophoresed and visualized a subset of PCR products on a 1.5% agarose gel stained with GelRed® (Biotium, Fremont, CA, USA) to ensure successful amplification and correct product sizes as well as lack of contamination.

Post-PCR library preparation and sequencing was conducted at the Georgia Genomics and Bioinformatics Core (GGBC, UG Athens, GA, RRID:SCR_010994). In short, provided PCR amplicons were cleaned using AMPure XP magnetic beads (Beckman Coulter, Indianapolis, IN, USA), barcoded with Nextera adapters (Illumina, San Diego, CA, USA) during a second PCR (3 min at 95°C; 15 cycles of 30 sec at 95°C, 30 sec at 67°C, and 30 sec at 72°C; and 4 min at 72°C), cleaned again using AMPureXP magnetic beads, and pooled in equimolar ratio. The resulting library was sequenced on a MiSeq PE 2x250bp (500 cycles) using Reagent Kit V2 with 25% PhiX spike-in (Illumina, San Diego, CA, USA). Given our technical replication of samples and controls, our final library included 6 negative field controls (1 at beginning and end of field sampling, amplified in triplicate), 12 negative extraction controls (1 in each of 4 extraction sets, amplified in triplicate), 2 positive PCR controls (1 in each of 2 amplification batches), 2 no-template negative PCR controls (1 in each of 2 amplification batches), and 159 samples (53 field samples, amplified in triplicate).

2.5 Bioinformatics

We processed sequencing data using the Anacapa Toolkit, which contains two core modules: one for quality control and ASV parsing, and one for classifying taxonomy (Curd et al., 2019). Briefly, we ran the first module using default parameters, which uses cutadapt (version 1.16) (Martin, 2011) for adapter and primer trimming, FastX-Toolkit (version: 0.0.13) (citation) for quality trimming, and dada2 (version 1.6) (Callahan et al., 2016) for assigning ASVs. For the second module, we utilized the MIDORI2 reference database, a quality controlled and updated database built from GenBank release 253 (20 December 2022) that has been technically validated (Leray et al., 2022). Following Gold et al. (2022), we adjusted the identity and query coverage to 95% (default: 80%) to account for the relative incompleteness of the broad COI reference database compared to more taxonomically-specific databases (Curd et al., 2019). The second module relies on Bowtie 2 (version 2.3.5) (Langmead and Salzberg, 2012) and a modified instance of BLCA (Gao et al., 2017) as dependencies. Following Gold et al. (2021a) we only kept taxonomic assignments that had a bootstrap confidence cutoff score of 60 or higher in BLCA, to avoid spurious assignments from the incomplete reference database. We modified the Anacapa Container (Ogden, 2018), a Singularity container with all the needed dependencies for executing the Anacapa Toolkit, to enable the pipeline to be run in a high-performance computing environment requiring two-step authentication; the updated container, scripts, and reference database with the required Bowtie 2 index library needed to reproduce our bioinformatics process can be found on Dryad (link/citation).

Raw ASVs, taxonomy assignments, and metadata were converted into interchangeable ampvis2 (version 2.8.6 packageVersion("ampvis2")) (Andersen et al., 2018) and phyloseq (version 1.46.0 packageVersion("phyloseq")) (McMurdie and Holmes, 2013) objects in R version 4.3.1 (2023-06-16) R.Version()$version.string to facilitate decontamination and further analyses. Singletons were removed using ampvis2, and samples were further decontaminated using phyloseq by removing all ASVs that appeared in any negative field control, negative extraction control, or no-template negative PCR control, a choice made due to the very low number of overlapping ASVs between samples and negative controls (Table S1). Samples were rarified to the minimum number of reads of any sample using ampvis2. Subsequent analyses were robust to all three decontamination steps.

### Importing Anacapa###
# Read in Anacapa Pipeline Output and process into ampvis2 objects for use in analyses

# Read in Anacapa Output
# Change p_confidence to switch to a different percent confidence output
###
p_confidence <- 60
###
current_subfolder <- "Data/Anacapa Pipeline Output/Tide Pool 5184 - 31 January 2023"

filepath <- paste0(
  current_subfolder,
  "/CO1/CO1_taxonomy_tables/Summary_by_percent_confidence/",
  p_confidence,
  "/CO1_ASV_raw_taxonomy_",
  p_confidence,
  ".txt"
)

AnacapaOutput <- read.table(filepath, header = TRUE, sep = "\t", dec = ".")

# Format ASV Table (extract just the needed information)
endcol <- ncol(AnacapaOutput) - 1
asvmat <- AnacapaOutput[, 2:endcol]
rownames(asvmat) <- AnacapaOutput[, 1]

# Format Taxonomy Table (extract just the needed information and rename columns)
endcol <- ncol(AnacapaOutput)
taxmat <- AnacapaOutput[, endcol]
taxmat <- str_split_fixed(taxmat, ";", 7)
colnames(taxmat) <- c("Kingdom", "Phylum", "Class", "Order", "Family", "Genus", "Species")
rownames(taxmat) <- rownames(asvmat)

# Read Metadata (saved in multiple different files)

current_subfolder <- paste0(current_subfolder, "/Metadata-Added/PillarPoint_SampleInfo_")

filepath <- paste0(current_subfolder, "EnviroData.txt")
EnviroData <- read.table(filepath, header = TRUE, sep = "\t", dec = ".", strip.white = TRUE)

filepath <- paste0(current_subfolder, "FieldSampling.txt")
FieldSampling <- read.table(filepath, header = TRUE, sep = "\t", dec = ".", strip.white = TRUE)
FieldSampling <- FieldSampling[, 1:4]

filepath <- paste0(current_subfolder, "Sequencing.txt")
Sequencing <- read.table(filepath, header = TRUE, sep = "\t", dec = ".", strip.white = TRUE)

filepath <- paste0(current_subfolder, "Location.txt")
Location <- read.table(filepath, header = TRUE, sep = "\t", dec = ".", strip.white = TRUE)

# Format Metadata
sampledata <- merge(FieldSampling, EnviroData, all = T)
sampledata <- sampledata %>% drop_na(Dereplicated_Sample_Name)
# removing one sample that has EnviroData reading but the field sample was not processed

sampledata <- merge(Sequencing, sampledata, all = T)
rownames(sampledata) <- sampledata[, "X"]

sampledata$Dereplicated_Sample_Name <- as.factor(sampledata$Dereplicated_Sample_Name)
sampledata$Type <- as.factor(sampledata$Type)
sampledata$PCR <- as.factor(sampledata$PCR)
sampledata$Time <- as.factor(sampledata$Time)
sampledata$Location <- as.factor(sampledata$Location)
sampledata$Extraction <- as.factor(sampledata$Extraction)
sampledata$SiteByTime <- as.factor(paste(sampledata$Location, sampledata$Time))

# Make ampvis2 objects without any pre-processing
asvmat_amp <- tibble::rownames_to_column(asvmat, "ASV")
sampledata_amp <- tibble::rownames_to_column(sampledata, "Sample")
taxmat_amp <- tibble::rownames_to_column(as.data.frame(taxmat), "ASV")
amp <- amp_load(asvmat_amp, metadata = sampledata_amp, taxonomy = taxmat_amp)

amp_nocontrols <- amp_filter_samples(amp, Type %in% c("sample"))
## 22 samples and 3315 OTUs have been filtered 
## Before: 181 samples and 71947 OTUs
## After: 159 samples and 68632 OTUs
amp_controls <- amp_filter_samples(amp, Type %in% c("control"))
## 159 samples and 68607 OTUs have been filtered 
## Before: 181 samples and 71947 OTUs
## After: 22 samples and 3340 OTUs
# Make ampvis2 objects with singletons removed
amp_NS <- amp_load(asvmat_amp, metadata = sampledata_amp, taxonomy = taxmat_amp, pruneSingletons = TRUE)
## 41532 singletons have been removed
amp_nocontrols_NS <- amp_filter_samples(amp_NS, Type %in% c("sample"))
## 22 samples and 381 OTUs have been filtered 
## Before: 181 samples and 30415 OTUs
## After: 159 samples and 30034 OTUs
amp_controls_NS <- amp_filter_samples(amp_NS, Type %in% c("control"))
## 159 samples and 30009 OTUs have been filtered 
## Before: 181 samples and 30415 OTUs
## After: 22 samples and 406 OTUs
# Make ampvis2 objects with a full decontamination procedure

# Function that removes any ASV that appears in any control from all samples
full_decontamination <- function(amp) {
  physeq <- amp_to_phyloseq(amp, NULL, NULL, NULL)

  physeq_controls <- physeq %>%
    subset_samples(Type == "control") %>%
    prune_taxa(taxa_sums(.) > 0, .)

  badASV <- taxa_names(physeq_controls)
  allASV <- taxa_names(physeq)
  allASV <- allASV[!(allASV %in% badASV)]
  physeq_FD <- prune_taxa(allASV, physeq)

  av2_otutable <- data.frame(otu_table(physeq_FD)@.Data)
  av2_taxtable <- data.frame(tax_table(physeq_FD)@.Data)
  av2_metadata <- data.frame(sample_data(physeq_FD))

  amp_return <- amp_load(av2_otutable, metadata = av2_metadata, taxonomy = av2_taxtable)
  amp_return <- amp_filter_samples(amp_return, Type %in% c("sample"))

  return(amp_return)
}

amp_nocontrols_FD <- full_decontamination(amp)
## 22 samples and 0 OTUs have been filtered 
## Before: 181 samples and 68607 OTUs
## After: 159 samples and 68607 OTUs
amp_nocontrols_NS_FD <- full_decontamination(amp_NS)
## 22 samples and 0 OTUs have been filtered 
## Before: 181 samples and 30009 OTUs
## After: 159 samples and 30009 OTUs
# Make ampvis2 objects by rarefying to the minimum number of reads of any sample

# Function that wraps around an ampvis2 function to rarefy samples to the minimum number of reads of any sample
rarefaction <- function(amp) {
  set.seed(0)
  reads <- colSums(amp$abund)
  minreads <- min(reads)
  amp_R <- amp_subset_samples(amp, rarefy = minreads)
  return(amp_R)
}

amp_nocontrols_R <- rarefaction(amp_nocontrols)
## 0 samples have been filtered.
amp_nocontrols_NS_R <- rarefaction(amp_nocontrols_NS)
## 0 samples have been filtered.
amp_nocontrols_FD_R <- rarefaction(amp_nocontrols_FD)
## 0 samples have been filtered.
amp_nocontrols_NS_FD_R <- rarefaction(amp_nocontrols_NS_FD)
## 0 samples have been filtered.
### Making GBIF Data Frames###
## Create data frames for submission to GBIF
# Export version of data with decontamination and controls removed but no additional processing

GBIF_export <- amp_nocontrols_FD

GBIF_export$metadata <- merge(GBIF_export$metadata, Location, all = T)

TimeZone <- "UTC−08:00"
Date <- "28 January 2022"
GBIF_export$metadata <- cbind(GBIF_export$metadata, TimeZone)
GBIF_export$metadata <- cbind(GBIF_export$metadata, Date)

names(GBIF_export$metadata)[names(GBIF_export$metadata) == "Sample"] <- "Sequencing_Sample_Name"

col_order <- c("Sequencing_Sample_Name", "Sample_Name", "Location", "Latitude", "Longitude", "CRS", "Date", "Time", "TimeZone", "T", "S")
GBIF_export$metadata <- GBIF_export$metadata[, col_order]

# Add sequences to file

current_subfolder <- "Data/Anacapa Pipeline Output/Tide Pool 5184 - 31 January 2023"
filepath <- paste0(
  current_subfolder,
  "/CO1/CO1_taxonomy_tables/CO1_ASV_taxonomy_detailed.txt"
)

AnacapaDetailed <- read.table(filepath, header = TRUE, sep = "\t", dec = ".")
sequences <- as.data.frame(AnacapaDetailed[, c("sequence", "sequencesF", "sequencesR")])
rownames(sequences) <- AnacapaDetailed$CO1_seq_number

GBIF_export$tax <- merge(sequences, GBIF_export$tax, by = "row.names", all.x = FALSE, all.y = TRUE, sort = FALSE)
rownames(GBIF_export$tax) <- GBIF_export$tax$Row.names

col_order <- c("sequence", "sequencesF", "sequencesR", "Kingdom", "Phylum", "Class", "Order", "Family", "Genus", "Species")
GBIF_export$tax <- GBIF_export$tax[, col_order]



if (!dir.exists("Analysis Products/Processed eDNA/GBIF")) {
  dir.create("Analysis Products/Processed eDNA/GBIF", recursive = TRUE)
}
write.csv(GBIF_export$abund, "Analysis Products/Processed eDNA/GBIF/ASVTable.csv", row.names = TRUE)
write.csv(GBIF_export$tax, "Analysis Products/Processed eDNA/GBIF/TaxTable.csv", row.names = TRUE)
write.csv(GBIF_export$metadata, "Analysis Products/Processed eDNA/GBIF/SampleData.csv", row.names = FALSE)

To ensure the accuracy of taxonomic assignments, we analyzed occurrence data from the Global Biodiversity Information Facility to investigate whether identified species had occurrence records in the California Current System and known ranges that encompassed Pillar Point, using the spocc (version 1.2.2 packageVersion("spocc")) (Chamberlain, 2021) package. A phylogenetic tree based on taxonomic assignments was created using the taxize (version 0.9.100 packageVersion("taxize")) (Chamberlain and Szöcs, 2013) and ggtreeExtra 1.12.0 packageVersion("ggtreeExtra") (citation) packages.

Data Analysis

To understand whether eDNA signals could be distinguished by location, we first analyzed individual-level differences between locations; that is, whether ASVs or individual taxa (agglomerated species-level taxonomic assignments) were unique to, or associated with, particular locations. We calculated and visualized unique ASVs and taxa using the eulerr (version 7.0.0 packageVersion("eulerr")) (Larsson, 2022) package. However, with metabarcoding data in particular, taxa or ASVs that are unique to a given location are not necessarily ecologically meaningful; they could include rare taxa present elsewhere but not amplified and exclude taxa that are well correlated with particular locations but sometimes detected at others. Thus, we also analyzed ASVs and taxa using an indicator species framework (Dufrêne and Legendre, 1997). In this framework, the null hypothesis is that the frequency of a taxon’s or ASV’s presence in samples from a particular location is not higher that the frequency of that taxon’s or ASV’s presence in samples from other locations. For each location, we identified all statistically-significant indicator taxa and ASVs with indicator value indices above 0.7—that is, indicators that are well-associated with a site group even if they are detected in samples from other sites—based on presence-absence data per sample using the indicspecies package (version 1.7.14 packageVersion("indicspecies")) (Cáceres and Legendre, 2009).

We followed our individual-level analyses with approaches to test whether community composition varied by location. We calculated a Jaccard dissimilarity matrix across all samples using vegan (version 2.6.4 packageVersion("vegan")) (Oksanen et al., 2022). Then, we tested for differences in community composition among locations using a permutational multivariate analysis of variance (PERMANOVA) with the model eDNA Presence ~ Location + Time + Biological Replicates using the adonis function in vegan. We confirmed that locational differences found via PERMANOVA were not a result of differences in dispersions by testing for homogeneity of dispersions using the betadisper function in vegan. We also visualized Jaccard dissimilarity using non-metric multidimensional scaling (NMDS) using the metaMDS function in vegan. We coupled these analyses with a partitioning among medoids algorithm (Kaufman and Rousseeuw, 1990) implemented with the pam function in the cluster package (version 2.1.6 packageVersion("cluster")) (Maechler et al., 2022). Rather than assuming location clusters a priori, we validated the optimal number of clusters for a given dataset by finding the number of clusters (k) that maximized the average silhouette width, a measure of how well-structured the clusters are. Finally, to better understand how the difference between locations varied over the time sampled, for each time point, we calculated the Jaccard dissimilarity between each unique combination of replicates within each site, and then the pairwise Jaccard dissimilarity between each unique combination of samples across the three pairs of sites: S1-N, S2-N, and S1-S2.

To further understand whether differences in eDNA detections corresponded with underlying ecological gradients, we compared the unique and indicator taxa identified at each site to their ecological zonation in a highly regarded field guide to the Pacific intertidal, Between Pacific Tides (Ricketts et al., 1985). To account for potential variations in taxonomic names between Between Pacific Tides and the MIDORI2 reference database, we used the World Register of Marine Species (WoRMS) to identify all synonymized names for each unique and indicator taxon identified, and we searched Between Pacific Tides for all synonyms. We compared the proportion of high and middle intertidal species identified across each location using a chi-squared test with p-values computed via Monte Carlo simulation.

Results

3.1 Sequencing Results & Taxonomic Diversity

### Full Output Metrics###
# Generate information about the full Anacapa Pipeline results

# Gather information about full Anacapa Pipeline results before any processing
total_ASVs <- nrow(amp$abund)
total_reads <- sum(amp$abund)

samples <- length(amp$metadata$Type[amp$metadata$Type == "sample"])
controls <- length(amp$metadata$Type[amp$metadata$Type == "control"])

# Check positive PCR controls
amp_MC <- amp_filter_samples(amp, Location %in% c("MC"))
## 179 samples and 71797 OTUs have been filtered 
## Before: 181 samples and 71947 OTUs
## After: 2 samples and 150 OTUs
df <- merge(amp_MC$abund, amp_MC$tax, by = "row.names")
df <- df[, c(2:3, 10)]
colnames(df) <- c("MC1", "MC2", "Species")
agg_df <- df %>%
  group_by(Species) %>%
  summarise(MC1_Reads = sum(MC1), MC2_Reads = sum(MC2)) %>%
  arrange(desc(MC1_Reads))
agg_df[agg_df == ""] <- "No Taxonomic Assignment"
agg_df$Species <- remove_NCBInums(agg_df$Species)
agg_df
amp_no_MC <- amp_filter_samples(amp, !(Location %in% c("MC")))
## 2 samples and 150 OTUs have been filtered 
## Before: 181 samples and 71947 OTUs
## After: 179 samples and 71797 OTUs
if (length(intersect(rownames(amp_MC$abund), rownames(amp_no_MC$abund))) == 0) {
  MC_overlap <- "no ASVs present in the positive PCR controls occurred in any other samples, providing no evidence of index hopping"
} else {
  MC_overlap <- "some ASVs present in the positive PCR controls occurred in other samples, providing evidence of index hopping (CHECK THIS)"
}

# Check intersection between samples and controls
intersect <- intersect(rownames(amp_controls$abund), rownames(amp_nocontrols$abund))
overlap <- length(intersect)

overlap_table <- data.frame(ASV = intersect, "Taxonomic Assignment" = amp_nocontrols$tax[amp_nocontrols$tax$OTU %in% intersect, ]$Species)
overlap_table$Taxonomic.Assignment <- remove_NCBInums(overlap_table$Taxonomic.Assignment)
overlap_table

Using the Anacapa Toolkit, we identified 71947 (total_ASVs) ASVs from 9291419(total_reads) reads across 159 (samples) samples and 22 (controls) controls (positive PCR controls, negative field controls, negative extraction controls, and no-template negative PCR controls). All expected taxa amplified in each positive PCR control, and no ASVs present in the positive PCR controls occurred in any other samples, providing no evidence of index hopping (MC_overlap). Before application of any decontamination steps, only 25 (overlap) ASVs were shared between the samples and negative field, extraction, and PCR controls.

### Core Data Sets###
# Establish processed data set used throughout analyses

data_amp <- amp_nocontrols_NS_FD_R

data_physeq <- amp_to_phyloseq(data_amp, NULL, NULL, NULL)

data_amp_taxa <- data_amp
data_amp_taxa$abund <- aggregate_abund(data_amp$abund, data_amp$tax, tax_aggregate = "Species", format = "abund")
## 24191 OTUs (out of 27038) with no assigned taxonomy at Species level were removed before aggregating OTUs
if (!dir.exists("Analysis Products/Processed eDNA/Manuscript Analysis")) {
  dir.create("Analysis Products/Processed eDNA/Manuscript Analysis", recursive = TRUE)
}
write.csv(data_amp$abund, "Analysis Products/Processed eDNA/Manuscript Analysis/ASVTable.csv", row.names = TRUE)
write.csv(data_amp$tax, "Analysis Products/Processed eDNA/Manuscript Analysis/TaxTable.csv", row.names = TRUE)
write.csv(data_amp$metadata, "Analysis Products/Processed eDNA/Manuscript Analysis/SampleData.csv", row.names = FALSE)
### Figure 3--Continued###
# Finish the bottom portion of Figure 3 now that data has been loaded

data_forchart <- amp$metadata[!is.na(amp$metadata$Time), ]

data_forchart <- data_forchart %>%
  group_by(SiteByTime) %>%
  mutate(chart_num = ceiling(row_number() / 3))

facet.labs <- c("Tide Pool 1\n (S1)", "Tide Pool 2\n (S2)", "Nearshore\n (N)", "Field Blank")
names(facet.labs) <- c("S1", "S2", "N", "FB")

data_forchart$Location <- factor(data_forchart$Location, levels = c("S1", "S2", "N", "FB"))
data_forchart$chart_num <- factor(data_forchart$chart_num, levels = c("3", "2", "1"))

sample_schema <- ggplot(data = data_forchart, aes(
  x = Time, y = chart_num, shape = Location,
  color = Time,
  fill = after_scale(alpha(colour, 0.05))
)) +
  geom_beeswarm(cex = 2, size = 3) +
  geom_box(
    aes(
      xmin = after_stat(x) - 0.45,
      xmax = after_stat(x) + 0.45,
      ymin = after_stat(y) - 0.45,
      ymax = after_stat(y) + 0.45
    ),
    radius = unit(5, "pt")
  ) +
  scale_shape_manual(values = c(15, 17, 16, 18)) +
  scale_color_viridis_d(direction = -1, begin = 0, end = .97) +
  facet_grid(Location ~ .,
    scales = "free_y", space = "free_y",
    switch = "y", labeller = labeller(Location = facet.labs)
  ) +
  theme_void(base_size = 12) +
  theme(
    legend.position = "none",
    strip.text.y.left = element_text(angle = 0, hjust = 1, vjust = .9),
    plot.margin = margin(0, 0, 0, 0, "pt")
  )


combined <- (plot_spacer() + p_patch + plot_spacer() + plot_layout(widths = c(3, 50, 1))) / (plot_spacer() + sample_schema + plot_layout(widths = c(1, 50))) & theme(plot.margin = margin(0, 0, 0, 0, "pt"))


path <- "Figures/Figure3_full."
save_pdf_png(plot = combined, path = path, w = 169, h = 169, u = "mm", bg = "transparent", dpi = 600)
Figure 3: Graph of tide predictions during field sampling on 28 January 2022, with icons to indicate the sampling scheme
Figure 3: Graph of tide predictions during field sampling on 28 January 2022, with icons to indicate the sampling scheme
### Processed Output Metrics###
# Gather information about processed Anacapa Toolkit

processed_ASVs <- nrow(data_amp$abund)
processed_reads <- sum(data_amp$abund)

# Create a phyloseq object where all samples are combined into one
total <- as.data.frame(rowSums(data_amp$abund))
physeq_summed <- amp_to_phyloseq(NULL, total, data_amp$tax[, 1:7], NULL)

# Summarize the number of unassigned ASVs
kingdom <- as.data.frame(tax_table(physeq_summed)[, 1])
unassigned_ASVs <- kingdom %>%
  group_by(Kingdom) %>%
  summarise(n = n()) %>%
  mutate(freq = n / sum(n))

# Summarize number of unique taxa at each taxonomic level
unique <- apply(tax_table(physeq_summed), 2, function(x) length(unique(x[x != ""])))
### GBIF Set-Up###
# Create functions and datasets needed for GBIF analysis

# Create list of identified species
species_list <- unique(data_amp$tax$Species)
species_list <- remove_NCBInums(species_list)
species_list <- species_list[species_list != ""]
species_list <- sub("_", "-", species_list) # to address Pseudo_nitzchia error

# Standardize species names against GBIF backbone
species_GBIF <- name_backbone_checklist(species_list)
species_standardized <- species_GBIF$species[!is.na(species_GBIF$species)]
species_both <- species_GBIF[c("species", "verbatim_name")]

## Core GBIF checking function
distribution_check <- function(small_bound, big_bound, species, min_records, efficiency) {
  ## Function that checks GBIF given a particular geographic region
  boundary_function <- function(species, bounds) {
    no_data <- c()
    confirmed <- c()
    for (i in species) {
      print(i)
      occ <- occ(
        query = i,
        geometry = bounds,
        from = "gbif",
        limit = min_records,
        has_coords = TRUE,
        gbifopts = list(hasGeospatialIssue = FALSE)
      )
      occ.df <- occ2df(occ)
      if (nrow(occ.df) >= min_records) {
        confirmed <- append(confirmed, i)
      } else {
        no_data <- append(no_data, i)
      }
    }
    return(list(no_data = no_data, confirmed = confirmed))
  }

  ## Function that checks GBIF to confirm whether a particular location is within the range of observations
  range_function <- function(species) {
    CC.confirmed <- c()
    CC.not_confirmed <- c()
    CC.no_data <- c()
    limits <- c(10, 100, 1000, 10000)

    for (i in species) {
      track <- 0
      for (l in limits) {
        print(i)
        print(l)
        occ <- occ(i, from = "gbif", limit = l, has_coords = TRUE, gbifopts = list(hasGeospatialIssue = FALSE))
        occ.df <- occ2df(occ)
        if (nrow(occ.df) < min_records) {
          CC.no_data <- append(CC.no_data, i)
          print("no data")
          track <- 1
          break
        }
        bb_occ <- sp::bbox(cbind(occ.df$longitude, occ.df$latitude))
        if (bb_occ["x", "min"] < small_bound[1] &
          bb_occ["x", "max"] > small_bound[1] &
          bb_occ["y", "min"] < small_bound[4] &
          bb_occ["y", "max"] > small_bound[4]) {
          CC.confirmed <- append(CC.confirmed, i)
          print("confirmed")
          track <- 1
          break
        }
        if (nrow(occ.df) < l) {
          CC.not_confirmed <- append(CC.not_confirmed, i)
          print("not confirmed")
          track <- 1
          break
        }
      }
      if (track == 0) {
        CC.not_confirmed <- append(CC.not_confirmed, i)
        print("not confirmed")
      }
    }
    return(list(no_data = CC.no_data, not_confirmed = CC.not_confirmed, confirmed = CC.confirmed))
  }


  # Actual Steps
  PP <- boundary_function(species, small_bound)

  if (efficiency == TRUE) {
    CC <- boundary_function(PP[["no_data"]], big_bound)
  } else {
    CC <- boundary_function(species, big_bound)
  }

  if (efficiency == TRUE) {
    range_confirmed <- range_function(CC[["confirmed"]])
    range_unconfirmed <- range_function(CC[["not_confirmed"]])
    return(list(PP, CC, range_confirmed, range_unconfirmed))
  } else {
    range <- range_function(species)
    return(list(PP, CC, range))
  }
}

# Get the California Current System shape

CC_shape <- mr_features_get(type = "MarineRegions:lme", featureID = "lme.10", format = "json")

# check that it's the right polygon
class(CC_shape) <- "mr_geojson"
CC_shape <- mr_as_wkt(CC_shape)
pnt <- st_as_sfc(CC_shape, crs = 4326)
mapview(pnt)
# Simplify the polygon for use with GBIF
CC_shape_sp <- st_transform(pnt, crs = "+proj=aeqd +lat_0=53.6 +lon_0=12.7")
mapview(CC_shape_sp)
CC_shape_sp <- st_simplify(CC_shape_sp, preserveTopology = FALSE, dTolerance = 10000)
CC_shape_sp <- st_transform(CC_shape_sp, crs = 4326)
mapview(CC_shape_sp)
### GBIF Run###
# Run function that does GBIF analysis (this takes a long time; recommend running with job::job() when working in chunks)

distribution <- distribution_check(c(-122.50, 37.49, -122.49, 37.50), CC_shape_sp, species_standardized, 5, FALSE)
### GBIF Summary###
# Organize the GBIF analysis output

d <- distribution
PP <- d[[1]]$confirmed
CC <- d[[2]]$confirmed
range <- d[[3]]$confirmed
no_data <- d[[3]]$no_data

df_PP <- c()
df_CC <- c()
df_range <- c()
df_no_data <- c()
df_not_in_GBIF <- c()


for (s in species_both$species) {
  if (is.na(s)) {
    df_not_in_GBIF <- append(df_not_in_GBIF, TRUE)
    df_PP <- append(df_PP, NA)
    df_CC <- append(df_CC, NA)
    df_range <- append(df_range, NA)
    df_no_data <- append(df_no_data, NA)
    next
  } else {
    df_not_in_GBIF <- append(df_not_in_GBIF, FALSE)
  }

  if (s %in% PP) {
    df_PP <- append(df_PP, TRUE)
  } else {
    df_PP <- append(df_PP, FALSE)
  }

  if (s %in% CC) {
    df_CC <- append(df_CC, TRUE)
  } else {
    df_CC <- append(df_CC, FALSE)
  }

  if (s %in% range) {
    df_range <- append(df_range, TRUE)
  } else {
    df_range <- append(df_range, FALSE)
  }

  if (s %in% no_data) {
    df_no_data <- append(df_no_data, TRUE)
  } else {
    df_no_data <- append(df_no_data, FALSE)
  }
}

GBIF_summary <- data.frame(
  Species = species_both$verbatim_name,
  GBIFSpecies = species_both$species,
  PillarPointOccurrence = df_PP,
  CCSOccurrence = df_CC,
  Range = df_range,
  NoData = df_no_data,
  NotInGBIF = df_not_in_GBIF
)

percentages <- GBIF_summary %>%
  group_by(across(PillarPointOccurrence:NotInGBIF)) %>%
  summarise(count = n()) %>%
  ungroup() %>%
  mutate(per = count / sum(count))

known_summary <- as.numeric(GBIF_summary %>% filter(!is.na(GBIFSpecies)) %>% summarise(count = sum(Range == TRUE & CCSOccurrence == TRUE)))

Focused on just the 159 (samples) samples, we removed singletons and all 25 (overlap) ASVs that overlapped with negative controls (Supplemental Information X), and we rarefied samples to the minimum number of reads of any sample, leaving 27038 (processed_ASVs) ASVs and 4047981 (processed_reads) reads. 89.1% (sprintf("%0.1f%%", unassigned_ASVs[unassigned_ASVs$Kingdom == "",]$freq * 100)) of ASVs were unassigned, and the remainder included representatives from 28 (unique["Phylum"]) phyla, 59 (unique["Class"]) classes, 132 (unique["Order"]) orders, 234 (unique["Family"]) families, 325 (unique["Genus"]) genera, and 415 (unique["Species"]) species (Figure 4). A breakdown of the relative proportions of reads and ASVs assigned to each phyla can be found in Table 1. To ensure the accuracy of these taxonomic identifications, we confirmed that 293 (known_summary) of 415 (unique["Species"]) identified species (70.6% sprintf("%0.1f%%", known_summary/unique["Species"] * 100)) have occurrence records in the California Current System (CCS) and known ranges that encompass Pillar Point. (additional details in SI 1 and Table S2).

### TABLE 1###
# Create table with summary of reads, ASVs, and species by phyla

# Remove all unclassified ASVs and condense to phylum level
physeq_totalreads <- tax_glom(physeq_summed, taxrank = "Phylum", NArm = TRUE)
Phyla_Reads <- data.frame(
  Phyla = tax_table(physeq_totalreads)[, 2],
  Reads = rowSums(otu_table(physeq_totalreads))
)

physeq_totalASVs <- physeq_summed

otu_table(physeq_totalASVs)[otu_table(physeq_totalASVs) > 0] <- 1
physeq_totalASVs <- tax_glom(physeq_totalASVs, taxrank = "Phylum", NArm = TRUE)


Phyla_ASVs <- data.frame(Phyla = tax_table(physeq_totalASVs)[, 2], ASVs = rowSums(otu_table(physeq_totalASVs)))


physeq_speciesbyphyla <- physeq_summed
physeq_speciesbytaxa <- tax_glom(physeq_summed, taxrank = "Species", NArm = TRUE)
otu_table(physeq_speciesbytaxa)[otu_table(physeq_speciesbytaxa) > 0] <- 1
physeq_speciesbytaxa <- tax_glom(physeq_speciesbytaxa, taxrank = "Phylum", NArm = TRUE)

Phyla_Species <- data.frame(Phyla = tax_table(physeq_speciesbytaxa)[, 2], Species = rowSums(otu_table(physeq_speciesbytaxa)))


list <- list(Phyla_Reads, Phyla_ASVs, Phyla_Species)
full <- list %>% reduce(full_join, by = "Phylum")
full[is.na(full)] <- 0


full_sorted <- full[order(-full$Reads), ]

full_sorted <- full_sorted %>%
  mutate(Reads_Percent = scales::label_percent()(Reads / sum(Reads))) %>%
  mutate(ASVs_Percent = scales::label_percent()(ASVs / sum(ASVs))) %>%
  mutate(Species_Percent = scales::label_percent()(Species / sum(Species)))

full_sorted$Phylum <- remove_NCBInums(full_sorted$Phylum)
full_sorted$Phylum <- str_replace(full_sorted$Phylum, "phylum_", "Class: ")

col_order <- c("Phylum", "Reads", "Reads_Percent", "ASVs", "ASVs_Percent", "Species", "Species_Percent")

full_sorted <- full_sorted[, col_order]


write.csv(full_sorted, "Analysis Products/Table1.csv", row.names = FALSE)

full_sorted
### Figure 4###
# Create phylogenetic tree for all taxonomic assignments

options(getClass.msg = FALSE)

# Aggregate to species assignment and remove the NCBI identifiers
pt_physeq <- tax_glom(data_physeq, taxrank = "Species", NArm = FALSE)
tax_table(pt_physeq) <- tax_table(pt_physeq)[!tax_table(pt_physeq)[, "Kingdom"] == ""]


tax_table(pt_physeq)[tax_table(pt_physeq) == ""] <- NA
tax_table(pt_physeq) <- tax_table(pt_physeq)[!is.na(tax_table(pt_physeq)[, "Phylum"])]
numbers <- sub(".*_", "", tax_table(pt_physeq))

taxa <- apply(numbers, 1, function(x) tail(na.omit(x), 1))

tax_table(pt_physeq) <- remove_NCBInums(tax_table(pt_physeq))


taxa_classification <- classification(taxa, db = "ncbi")


taxa_tree <- class2tree(taxa_classification, check = TRUE)

# Change the tip labels to match phyloseq objects (code only works if order is the same)
taxa_tree$phylo$tip.label <- row.names(tax_table(pt_physeq))


phyla <- unique(tax_table(pt_physeq)[, "Phylum"])

phyla_nodes <- c()
phyla_nodes <- data.frame("node_phylum" = c(), "node" = c())
phyla_nodes_secondary <- data.frame("node_phylum" = c(), "tips" = c())

for (x in phyla) {
  OTUs <- na.omit(row.names(tax_table(pt_physeq))[tax_table(pt_physeq)[, "Phylum"] == x])
  OTUs <- as.vector(OTUs)
  num <- ape::getMRCA(taxa_tree$phylo, tip = OTUs)
  if (is.null(num)) {
    nodes <- as_tibble(taxa_tree$phylo)
    num <- nodes$node[nodes$label == OTUs]
  }
  df <- data.frame("node_phylum" = c(x), "node" = c(num))
  phyla_nodes <- rbind(phyla_nodes, df)

  if (length(OTUs) < 6) {
    for (y in OTUs) {
      df2 <- data.frame("node_phylum" = c(x), "tips" = c(y))
      phyla_nodes_secondary <- rbind(phyla_nodes_secondary, df2)
    }
  }
}

pt_physeq <- merge_phyloseq(pt_physeq, taxa_tree$phylo)

# Use Polychrome package to create a good color palette for the number of phyla
set.seed(567629)
colors <- createPalette(28, c("#FFFFFF"), range = c(30, 80), target = c("normal", "protanope", "deuteranope", "tritanope"))

# Check whether the given order of colors has good contrast for different forms of colorblindness
pal.safe(colors)

# Manually re-order the colors to ensure there is good contrast between adjacent colors
colors_ordered <- colors[c(
  "NC2",
  "NC11",
  "NC27",
  "NC25",
  "NC4",
  "NC5",
  "NC8",
  "NC24",
  "NC9",
  "NC10",
  "NC12",
  "NC13",
  "NC1",
  "NC14",
  "NC15",
  "NC16",
  "NC7",
  "NC17",
  "NC18",
  "NC19",
  "NC20",
  "NC21",
  "NC22",
  "NC23",
  "NC26",
  "NC6",
  "NC3",
  "NC28"
)]

# Confirm that the new order works well
pal.safe(colors_ordered)

# Create ggtree
p <- ggtree::ggtree(pt_physeq, layout = "circular")

ordered_names <- ggtree::get_taxa_name(p)
ordered_names <- unique(ordered_names)
ordered_names[match(rownames(tax_table(pt_physeq)), ordered_names)] <- tax_table(pt_physeq)[, "Phylum"]
ordered_names <- unique(ordered_names)

names(colors_ordered) <- ordered_names

p <- p + geom_fruit(geom = geom_tile, mapping = aes(fill = Phylum), width = 3, show.legend = FALSE) +
  scale_fill_manual(values = colors_ordered) +
  scale_color_manual(values = colors_ordered)

p <- p + geom_fruit(data = phyla_nodes_secondary, geom = geom_tile, mapping = aes(y = tips, fill = node_phylum), width = 6, show.legend = FALSE)
p <- p + ggtree::geom_hilight(data = phyla_nodes, mapping = aes(node = node, fill = node_phylum), show.legend = FALSE)

p <- p + ggtree::geom_cladelab(data = phyla_nodes, mapping = aes(node = node, label = node_phylum), geom = "text", angle = "auto", offset = 5, fontsize = 2, barcolor = NA, show.legend = FALSE)

p <- p +
  theme(
    panel.background = element_rect(fill = "transparent"),
    plot.background = element_rect(fill = "transparent", color = NA),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    legend.background = element_rect(fill = "transparent"),
    legend.box.background = element_rect(fill = "transparent")
  )

path <- "Figures/Figure4."
save_pdf_png(plot = p, path = path, w = 169, h = 169, u = "mm", bg = "transparent", dpi = 600)
Figure 4: : Phylogenetic tree colored by the phyla identified across all eDNA samples. Italicized taxonomic names are those with no phylum-level assignment, so class-level assignments are used to differentiate (additional information added after R figure production)
Figure 4: : Phylogenetic tree colored by the phyla identified across all eDNA samples. Italicized taxonomic names are those with no phylum-level assignment, so class-level assignments are used to differentiate (additional information added after R figure production)

3.2 Individual-Level Differences Between Locations

### Euler Diagrams###

eulerr_options(quantities = list(fontsize = 10), legend = list(fontsize = 14))

# Subset ampvis2 data by location

amp_S1 <- amp_filter_samples(data_amp, Location %in% c("S1"))
## 108 samples and 14365 OTUs have been filtered 
## Before: 159 samples and 27038 OTUs
## After: 51 samples and 12673 OTUs
amp_S2 <- amp_filter_samples(data_amp, Location %in% c("S2"))
## 105 samples and 16586 OTUs have been filtered 
## Before: 159 samples and 27038 OTUs
## After: 54 samples and 10452 OTUs
amp_N <- amp_filter_samples(data_amp, Location %in% c("N"))
## 105 samples and 15230 OTUs have been filtered 
## Before: 159 samples and 27038 OTUs
## After: 54 samples and 11808 OTUs
# List the unique taxa at each location

S1_taxa <- unique(amp_S1$tax$Species)
S1_taxa <- S1_taxa[S1_taxa != ""]
S2_taxa <- unique(amp_S2$tax$Species)
S2_taxa <- S2_taxa[S2_taxa != ""]
N_taxa <- unique(amp_N$tax$Species)
N_taxa <- N_taxa[N_taxa != ""]

# List the unique ASVs at each locaton

S1_ASV <- unique(amp_S1$tax$OTU)
S2_ASV <- unique(amp_S2$tax$OTU)
N_ASV <- unique(amp_N$tax$OTU)


# Using eulerr, create euler diagrams for taxa and ASVs

add_quantity_line_break <- function(v) {
  tags <- v$children$canvas.grob$children$diagram.grob.1$children$tags$children

  tags <- do.call(grid::gList, lapply(tags, function(x) {
    x$children[[2]]$label <- sub(" \\%)", "%)", x$children[[2]]$label)
    before <- gsub(" .*$", "", x$children[[2]]$label)
    after <- gsub(".*\\(", "(", x$children[[2]]$label)
    full <- bquote(atop(NA, atop(atop(textstyle(.(before)), textstyle(italic(.(after)))), NA)))

    x$children[[2]]$label <- full
    x$children[[2]]$just <- NULL
    x
  }))

  v$children$canvas.grob$children$diagram.grob.1$children$tags <- tags

  return(v)
}

E_taxa <- euler(list(S1 = S1_taxa, S2 = S2_taxa, N = N_taxa), shape = "ellipse")
E_taxa_plot <- plot(E_taxa, quantities = list(type = c("counts", "percent"), cex = 1), legend = list(side = "right", nrow = 1, ncol = 3, cex = 1))
E_taxa_plot <- add_quantity_line_break(E_taxa_plot)

unique_taxa_location <- (E_taxa$original.values["S1"] +
  E_taxa$original.values["S2"] +
  E_taxa$original.values["N"]) / sum(E_taxa$original.values)


E_ASV <- euler(list(S1 = S1_ASV, S2 = S2_ASV, N = N_ASV), shape = "ellipse")
E_ASV_plot <- plot(E_ASV, quantities = list(type = c("counts", "percent"), cex = 1), legend = list(side = "right", nrow = 1, ncol = 3, cex = 1))
E_ASV_plot <- add_quantity_line_break(E_ASV_plot)

unique_ASV_location <- (E_ASV$original.values["S1"] +
  E_ASV$original.values["S2"] +
  E_ASV$original.values["N"]) / sum(E_ASV$original.values)

Across both taxa (n=r unique["Species"]``unique["Species"]) and ASVs (n=27038 processed_ASVs), all three locations had unique elements, suggesting that there was not complete mixing of eDNA across micro-habitats. 33.3% sprintf("%0.1f%%", unique_taxa_location * 100) of taxa and 79.1% sprintf("%0.1f%%", unique_ASV_location * 100) of ASVs were unique to one of the three locations (Figure 5). At both the taxa and ASV level, S1 had more unique elements than S2 and nearshore, although this effect was more pronounced across ASVs. ASVs and taxa shared across pairs of two locations were the least common elements.

euler <- (wrap_elements(panel = grid::textGrob("A)", hjust = 6, vjust = 1, gp = gpar(fontsize = 14, fontface = "bold"))) +
  wrap_elements(panel = grid::textGrob("B)", hjust = 6, vjust = 1, gp = gpar(fontsize = 14, fontface = "bold")))) /
  (wrap_elements(panel = E_taxa_plot$children$canvas.grob) + wrap_elements(panel = E_ASV_plot$children$canvas.grob)) /
  wrap_elements(panel = E_taxa_plot$children$legend.grob) + plot_layout(heights = c(1, 10, 1))

path <- "Figures/Figure5."
save_pdf_png(plot = euler, path = path, w = 169, h = 110, u = "mm", bg = "transparent", dpi = 600)
Figure 5: Area-proportional Euler diagrams showing the overlap in taxa (A) and ASVs (B) between locations S1, S2, and N.
Figure 5: Area-proportional Euler diagrams showing the overlap in taxa (A) and ASVs (B) between locations S1, S2, and N.
# Function for creating indicator species heatmap from physeq data

indicator_heatmap <- function(physeq, asv) {
  # If analyzing by taxa, remove all unclassified ASVs and condense to species assignments
  if (asv == FALSE) {
    physeq <- tax_glom(physeq, taxrank = "Species", NArm = TRUE)
    tax_table(physeq) <- remove_NCBInums(tax_table(physeq))
    # tax_table(physeq) = gsub("\\_.*","",tax_table(physeq))
  } else {
    tax_table(physeq) <- remove_NCBInums(tax_table(physeq))
  }

  # Convert to presence/absence data
  otu_table(physeq)[otu_table(physeq) > 0] <- 1

  # Use indicspecies package to get top taxa
  indval <- multipatt(t(otu_table(physeq)), t(sample_data(physeq)[, "Location"]), control = how(nperm = 999), duleg = TRUE)
  top_N <- rownames(indval$sign %>% filter(p.value < 0.05) %>% filter(s.N == 1) %>% filter(stat > .7))
  top_S1 <- rownames(indval$sign %>% filter(p.value < 0.05) %>% filter(s.S1 == 1) %>% filter(stat > .7))
  top_S2 <- rownames(indval$sign %>% filter(p.value < 0.05) %>% filter(s.S2 == 1) %>% filter(stat > .7))

  indicators_all <- c(top_N, top_S1, top_S2)

  # Merge samples by site/time before plotting
  physeq_merge <- merge_samples(physeq, "SiteByTime")

  # Update metadata accordingly
  updated_metadata <- as.matrix(sample_data(physeq)[, c("SiteByTime", "Time", "Location", "T", "S")])
  updated_metadata <- as.data.frame(updated_metadata)
  updated_metadata$SiteByTime <- as.factor(updated_metadata$SiteByTime)
  updated_metadata$Time <- as.factor(updated_metadata$Time)
  updated_metadata$Location <- as.factor(updated_metadata$Location)
  updated_metadata <- distinct(updated_metadata)
  rownames(updated_metadata) <- updated_metadata[, "SiteByTime"]
  sample_data(physeq_merge) <- sample_data(updated_metadata)

  # Divide all merged samples by the number of samples they represent
  otu_table(physeq_merge) <- otu_table(physeq_merge) / 3

  otu_table(physeq_merge)[grepl("11:30", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("11:30", rownames(otu_table(physeq_merge)))] / 3

  otu_table(physeq_merge)[grepl("14:00", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("14:00", rownames(otu_table(physeq_merge)))] / 3

  otu_table(physeq_merge)[grepl("17:00", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("17:00", rownames(otu_table(physeq_merge)))] / 3

  # Add labels to the indicator species for plotting
  indicators_only <- prune_taxa(colnames(otu_table(physeq_merge)) %in% indicators_all, physeq_merge)

  add_indicator_label <- function(X) {
    if (X %in% top_N) {
      return("N")
    } else if (X %in% top_S1) {
      return("S1")
    } else if (X %in% top_S2) {
      return("S2")
    } else {
      return("NA")
    }
  }

  indicators <- sapply(rownames(tax_table(indicators_only)), add_indicator_label)

  tax_table(indicators_only) <- cbind(tax_table(indicators_only), indicators)

  # Plot
  plot <- plot_heatmap(indicators_only,
    method = NULL,
    distance = NULL,
    trans = NULL,
    taxa.order = rev(indicators_all),
    taxa.label = "Species",
    sample.label = "Time",
    sample.order = "Time"
  ) +
    facet_grid(factor(indicators, levels = c("S1", "S2", "N")) ~ factor(Location, levels = c("S1", "S2", "N")),
      scales = "free",
      space = "free",
      switch = "y"
    ) +
    scale_fill_gradient(low = "black", high = "#B5D7E4") +
    theme_grey(base_size = 10) +
    theme(plot.title = element_text(hjust = 0.5)) +
    theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
    theme(strip.placement = "outside") +
    theme(strip.text = element_text(size = rel(1))) +
    theme(legend.position = "bottom") +
    theme(panel.background = element_blank(), panel.grid.major = element_blank()) +
    labs(fill = "Proportion of Positive Detects", title = "Locations") +
    theme(
      axis.ticks = element_line(color = "black"),
      axis.text.y = element_text(color = "black", face = "italic"),
      axis.text.x = element_text(color = "black")
    ) +
    guides(fill = guide_colorbar(barwidth = 10))

  plot$scales$scales[[2]]$name <- "Indicators"

  return(list(
    plot = plot,
    top_N = top_N,
    top_S1 = top_S1,
    top_S2 = top_S2,
    all_indicators = indicators_all,
    full_output = indval
  ))
}

heatmap_taxa <- indicator_heatmap(data_physeq, FALSE)
heatmap_ASV <- indicator_heatmap(data_physeq, TRUE)

indicator_ASVs <- data_amp$tax[heatmap_ASV$all_indicators, ]
unassigned_indicator_ASVs <- indicator_ASVs %>%
  group_by(Kingdom) %>%
  summarise(n = n()) %>%
  mutate(freq = n / sum(n))


identify_new_indicators <- function(data_amp, top_ASVs, top_taxa) {
  top_ASVs <- data_amp$tax[top_ASVs, ]
  top_taxa <- data_amp$tax[top_taxa, ]

  top_ASVs <- top_ASVs$Species[top_ASVs$Species != ""]
  top_taxa <- top_taxa$Species

  top_ASVs <- remove_NCBInums(top_ASVs)
  top_taxa <- remove_NCBInums(top_taxa)
  return(setdiff(top_ASVs, top_taxa))
}

N_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_N, heatmap_taxa$top_N))
S1_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_S1, heatmap_taxa$top_S1))
S2_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_S2, heatmap_taxa$top_S2))
path <- "Figures/Figure6."
save_pdf_png(plot = heatmap_taxa$plot, path = path, w = 169, h = 100, u = "mm", bg = "transparent", dpi = 600)
Figure 6: Heat map of identified indicator taxa for all three locations over time, scaled by the number of replicates that detected that species.
Figure 6: Heat map of identified indicator taxa for all three locations over time, scaled by the number of replicates that detected that species.

Using an indicator species framework produced similar trends to the analysis of unique taxa and ASVs; all three locations had indicator taxa and ASVs, and S1 had more indicator elements than other locations. By taxa, we identified 11 length(heatmap_taxa$all_indicators) indicator taxa: 7 length(heatmap_taxa$top_S1) for S1, 3 length(heatmap_taxa$top_S2) for S2, and 1 length(heatmap_taxa$top_N) for nearshore (Figure 6). By ASVs, we found more indicators overall. We identified 99 length(heatmap_ASV$all_indicators) indicator ASVs: 72 length(heatmap_ASV$top_S1) for S1, 10 length(heatmap_ASV$top_S2) for S2, and 17 length(heatmap_ASV$top_N) for nearshore (Supplemental Figure X). Most (78.8% sprintf("%0.1f%%", unassigned_indicator_ASVs[unassigned_indicator_ASVs$Kingdom == "",]$freq * 100)) indicator ASVs had no taxonomic assignment, but the ones that did included several species beyond the original indicator taxa, at S1 (Bossiella frondescens, Bossiella plumosa, Corallina confusa, Leathesia difformis, Myrionema balticum, Scorpaenichthys marmoratus toString(S1_ASV_extra)), S2 (Bossiella frondescens, Smithora naiadum toString(S2_ASV_extra)), and nearshore (Halichondria panicea, Mazzaella splendens, Smithora naiadum, Strongylocentrotus purpuratus toString(N_ASV_extra)).

3.3. Community-Level Differences between Locations

# Calculate Jaccard dissimilarity matrices
jaccard_full <- vegdist(t(data_amp$abund), binary = TRUE, method = "jaccard")
jaccard_taxa <- vegdist(t(data_amp_taxa$abund), binary = TRUE, method = "jaccard")
set.seed(0)

# PERMANOVA on full data set
permutest(betadisper(jaccard_full, data_amp$metadata$Location))
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##            Df   Sum Sq    Mean Sq      F N.Perm Pr(>F)  
## Groups      2 0.002340 0.00117003 2.9267    999  0.061 .
## Residuals 156 0.062365 0.00039977                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis2(jaccard_full ~ Location + Time + Dereplicated_Sample_Name, data = data_amp$metadata)
# PERMANOVA on taxa data set
permutest(betadisper(jaccard_taxa, data_amp_taxa$metadata$Location))
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##            Df  Sum Sq    Mean Sq      F N.Perm Pr(>F)
## Groups      2 0.00061 0.00030272 0.1364    999  0.894
## Residuals 156 0.34626 0.00221963
adonis2(jaccard_taxa ~ Location + Time + Dereplicated_Sample_Name, data = data_amp_taxa$metadata)
# Check the stress vs. dimension plot

# Function that performs a NMDS for 1-10 dimensions and plots the nr of dimensions vs the stress
NMDS.scree <- function(x) { # where x is the name of the data frame variable
  plot(rep(1, 10), replicate(10, metaMDS(x, autotransform = F, k = 1)$stress), xlim = c(1, 10), ylim = c(0, 0.30), xlab = "# of Dimensions", ylab = "Stress", main = "NMDS stress plot")
  for (i in 1:10) {
    points(rep(i + 1, 10), replicate(10, metaMDS(x, autotransform = F, k = i + 1)$stress))
  }
}

# Use NMDS.scree function to choose the optimal nr of dimensions
NMDS.scree(jaccard_full)

NMDS.scree(jaccard_taxa)

# Establish functions for PAM clustering algorithm

PAM_validation <- function(dist) {
  k_list <- c()
  avg_sil_width <- c(0)
  for (x in 1:(nrow(as.matrix(dist)) - 1)) {
    PAM <- pam(dist, k = x, diss = TRUE)
    avg_sil_width <- c(avg_sil_width, PAM$silinfo$avg.width)
    k_list <- c(k_list, x)
  }

  PAM_validation <- data.frame(k = k_list, sil_width = avg_sil_width, x_max = which.max(avg_sil_width))
  return(PAM_validation)
}

PAM_validation_viz <- function(PAM_validation) {
  plot <- ggplot(
    data = PAM_validation,
    aes(x = k, y = sil_width)
  ) +
    geom_line() +
    geom_point() +
    xlab("K") +
    ylab("Average Silhouette Width") +
    ggtitle("Cluster Validation using Average Silhouette Width") +
    geom_segment(
      aes(
        x = x_max[1],
        y = 0,
        xend = x_max[1],
        yend = sil_width[x_max[1]],
        color = "red"
      ),
      linetype = 2,
      show.legend = FALSE
    )
  return(plot)
}

PAM_silhouette_viz_3 <- function(PAM, sample_data) {
  set.seed(0)
  PAM_df <- data.frame(PAM$silinfo$widths)
  PAM_df <- cbind(PAM_df, X = row.names(PAM_df))
  PAM_df <- merge(PAM_df, sample_data, by = "X")
  PAM_df$cluster <- as.factor(PAM_df$cluster)
  PAM_df$random <- sample(1000, size = nrow(PAM_df), replace = FALSE)


  ggplot(
    data = PAM_df,
    aes(x = sil_width, y = reorder(X, random), fill = Location)
  ) +
    geom_point(aes(shape = Location, color = Time), size = 2, position = position_jitter(height = 20, width = 0)) +
    scale_shape_manual(values = c(16, 15, 17)) +
    facet_grid(cluster ~ ., scales = "free_y", space = "free_y") +
    viridis::scale_color_viridis(discrete = TRUE, begin = 0, end = .97, direction = -1) +
    xlab("Silhouette Width") +
    ylab("") +
    geom_vline(xintercept = PAM$silinfo$avg.width, linetype = "dashed", color = "red") +
    theme_classic(base_size = 10) +
    theme(axis.text.x = element_text(angle = 0)) +
    ggtitle("PAM Clustering Visualization") +
    theme(
      axis.text.y = element_blank(),
      axis.ticks.y = element_blank(),
      panel.grid.major = element_blank(),
      panel.grid.minor = element_blank(),
      panel.background = element_blank(),
      panel.border = element_rect(colour = "black", size = 1, fill = NA)
    ) +
    scale_y_discrete(expand = expansion(add = 40))
}
NMDS_PAM <- function(amp, jaccard, dim, PAM_logical) {
  set.seed(0)
  NMDS <- metaMDS(jaccard, dim, trymax = 100, tidy = TRUE)

  NMDS_stress <- stressplot(NMDS)

  data.scores <- as.data.frame(scores(NMDS))
  data.scores$X <- rownames(data.scores)
  data.scores <- merge(data.scores, amp$metadata)

  annotations1 <- data.frame(
    xpos = c(Inf), ypos = c(-Inf),
    annotateText = c(paste("Stress:", round(NMDS$stress, 3))),
    hjustvar = c(1),
    vjustvar = c(-.5)
  )

  plot1 <- ggplot(data = data.scores, aes(x = NMDS1, y = NMDS2)) +
    theme_light() +
    geom_point(aes(shape = Location, color = Time), size = 2) +
    scale_shape_manual(values = c(16, 15, 17)) +
    theme(text = element_text(size = 10)) +
    ggtitle("A) nNMDS Ordination (Jaccard Dissimilarity)") +
    viridis::scale_color_viridis(discrete = TRUE, begin = 0, end = .97, direction = -1) +
    stat_ellipse(aes(group = Location), type = "t", linetype = 2, alpha = 1)


  plot1 <- plot1 +
    geom_text(data = annotations1, aes(x = xpos, y = ypos, hjust = hjustvar, vjust = vjustvar, label = annotateText)) +
    theme_classic(base_size = 10)

  if (PAM_logical == TRUE) {
    validated_k <- PAM_validation(jaccard)
    PAM_validation <- PAM_validation_viz(validated_k)

    PAM <- pam(jaccard, k = validated_k$x_max[1], diss = TRUE)
    plot2 <- PAM_silhouette_viz_3(PAM, amp$metadata)

    return(list(NMDS = plot1, PAM = plot2, NMDS_stress = NMDS_stress, PAM_validation = PAM_validation))
  }

  return(plot1)
}


NMDS_PAM_full <- NMDS_PAM(data_amp, jaccard_full, 2, TRUE)

NMDS_PAM_full$PAM_validation

NMDS_PAM_taxa <- NMDS_PAM(data_amp_taxa, jaccard_taxa, 2, TRUE)

NMDS_PAM_taxa$PAM_validation

NMDS_PAM_combined <- (NMDS_PAM_full$NMDS + theme(legend.position = "none") + ggtitle("A)")) +
  (NMDS_PAM_full$PAM + theme(legend.position = "none") + ggtitle("B)")) +
  (NMDS_PAM_taxa$NMDS + theme(legend.position = "none") + ggtitle("C)")) +
  (NMDS_PAM_taxa$PAM + ggtitle("D)")) +
  plot_layout(guides = "collect", widths = c(1, 1))

path <- "Figures/Figure7."
save_pdf_png(plot = NMDS_PAM_combined, path = path, w = 169, h = 169, u = "mm", bg = "transparent", dpi = 600)

Community composition also differed across locations, as supported by multiple analyses. Variation in community composition was significantly explained by location, even when accounting for variation due to time of sampling and variation between replicates (ASVs: PERMANOVA p < 0.001, betadisper p > 0.05; Taxa: PERMANOVA p < 0.001, betadisper p > 0.05). As visualized using NMDS ordination, S1 and S2 samples collected around low tide were most dissimilar from the offshore samples (Figures 7A, 7C). These patterns persisted in the optimal clusters identified using the partitioning among medoids (PAM) algorithm, without assuming a priori that location drives the clusters (Figure 7B, 7D). When analyzed by ASV, PAM identified three optimal clusters, primarily composed of: 1) nearshore samples with additional samples from S1 and S2 at early time points, 2) the remaining S1 samples, and 3) the remaining S2 samples (Figure 7B). When analyzing by taxa, PAM additionally differentiated between samples from the three locations collected at early time points. Thus, multiple analyses with different initial assumptions all demonstrated differentiable eDNA signals across micro-habitats.

Figure 7: : Ordination analysis (NMDS using Jaccard Distance; A, C) and cluster analysis (partitioning among medoids with number of clusters validated to maximize average silhouette width; B,D). Panels A & B are analyzed by ASV, and panels C & D are analyzed by taxa. 95% confidence ellipses for the centroids of each location based on a multivariate t-distribution are shown in the NMDS ordinations with black dashed lines, and average silhouette width is shown in cluster diagrams with a red dashed line.
Figure 7: : Ordination analysis (NMDS using Jaccard Distance; A, C) and cluster analysis (partitioning among medoids with number of clusters validated to maximize average silhouette width; B,D). Panels A & B are analyzed by ASV, and panels C & D are analyzed by taxa. 95% confidence ellipses for the centroids of each location based on a multivariate t-distribution are shown in the NMDS ordinations with black dashed lines, and average silhouette width is shown in cluster diagrams with a red dashed line.
distmat <- as.matrix(jaccard_full)

# Calculate Pairwise Dissimilarity Values Within and Across Sites

Jaccard <- c()
Combo <- c()
Time <- c()
summary <- data.frame(Jaccard, Combo, Time)

one <- c("S1", "S2", "N", "S1", "S2", "S1")
one_names <- c("S1", "S2", "N", "S1", "S2", "S1")
two <- c("S1", "S2", "N", "N", "N", "S2")
two_names <- c("S1", "S2", "N", "N", "N", "S2")

for (x in levels(data_amp$metadata$Time)) {
  subset <- filter(data_amp$metadata, data_amp$metadata$Time == x)

  for (i in 1:length(one)) {
    name <- paste(one_names[i], two_names[i], sep = ":")
    data <- distmat[subset$X[subset$Location == one[i]], subset$X[subset$Location == two[i]]]
    Jaccard <- vector()

    if (!(0 %in% dim(data))) {
      for (row in 1:nrow(data)) {
        for (col in 1:ncol(data)) {
          if (col > row) {
            Jaccard <- c(Jaccard, data[row, col])
          }
        }
      }
    }
    Combo <- rep(name, length(Jaccard))
    Time <- rep(x, length(Jaccard))

    summary <- rbind(summary, data.frame(Jaccard, Combo, Time))
  }
}


## PLOTTING

# Define palette for colors and fills
colors <- turbo(8)

palette <- c(
  "Within Site" = "#30123BFF",
  "S1:N" = "#1AE4B6FF",
  "S2:N" = "#FABA39FF",
  "S1:S2" = "#7A0403FF"
)

fill_palette <- c(
  "Within Site" = "#30123B20",
  "S1:N" = "#1AE4B620",
  "S2:N" = "#FABA3920",
  "S1:S2" = "#7A040320"
)


# WITHIN SITE COMBINED

summary$Combo2 <- summary$Combo
summary$Combo2[summary$Combo2 == "S1:S1"] <- "Within Site"
summary$Combo2[summary$Combo2 == "S2:S2"] <- "Within Site"
summary$Combo2[summary$Combo2 == "N:N"] <- "Within Site"

stats <- summary %>%
  filter(Combo2 == "Within Site") %>%
  summarize(mean = mean(Jaccard), max = max(Jaccard))


g2.5 <- ggplot(summary, aes(
  x = Time,
  y = Jaccard,
  color = factor(Combo2, level = c("Within Site", "S1:N", "S2:N", "S1:S2")),
  fill = factor(Combo2, level = c("Within Site", "S1:N", "S2:N", "S1:S2"))
)) +
  geom_boxplot(position = position_dodge(.5, preserve = "single")) +
  geom_point(position = position_jitterdodge(dodge.width = .5), alpha = 0.2) +
  scale_color_manual(values = palette, name = "Site Pairings") +
  scale_fill_manual(values = fill_palette, name = "Site Pairings") +
  geom_hline(yintercept = stats$mean, color = palette["Within Site"]) +
  ylab("Jaccard Dissimilarity") +
  coord_cartesian(expand = 0, clip = "off") +
  geom_text(
    aes(max(Time),
      stats$mean,
      label = "Mean Dissimilarity\n  Within Sites",
      hjust = -.2
    ),
    color = palette["Within Site"],
    show.legend = FALSE,
    check_overlap = TRUE
  ) +
  theme_classic(base_size = 12) +
  theme(
    axis.ticks = element_line(color = "black"),
    axis.text.y = element_text(color = "black"),
    axis.text.x = element_text(color = "black")
  ) +
  theme(legend.position = "right", legend.justification = "top")

path <- "Figures/Figure8."
save_pdf_png(plot = g2.5, path = path, w = 169, h = 120, u = "mm", bg = "transparent", dpi = 600)

The extent of the Jaccard dissimilarity between samples from different locations varied over time. As shown in Figure 8, except at the first time point sampled, the dissimilarity between samples across sites was always greater than the mean dissimilarity between samples within the same site, and increasingly so across the period sampled. At two time points—15:30 and 16:00—after low tide but before water was moving between all locations again, all dissimilarity values across sites were greater than the maximum dissimilarity recorded between two samples from the same site.

Figure 8: Box plots over time showing the pairwise Jaccard dissimilarity values between all unique pairs of replicates from the same sites (Within Site) and all unique pairs of samples across two sites (S1:O, S:O, S1:S2). The solid line depicts the mean Jaccard dissimilarity value from within site pairings.
Figure 8: Box plots over time showing the pairwise Jaccard dissimilarity values between all unique pairs of replicates from the same sites (Within Site) and all unique pairs of samples across two sites (S1:O, S:O, S1:S2). The solid line depicts the mean Jaccard dissimilarity value from within site pairings.

3.4. Ecological Significance

### Ecological Significance###

# NOT DONE YET

S1_unique <- setdiff(S1_taxa, union(S2_taxa, N_taxa))
S2_unique <- setdiff(S2_taxa, union(S1_taxa, N_taxa))
N_unique <- setdiff(N_taxa, union(S2_taxa, S1_taxa))


S1 <- data.frame(list(Species = remove_NCBInums(S1_unique), Unique = "S1"))
S2 <- data.frame(list(Species = remove_NCBInums(S2_unique), Unique = "S2"))
N <- data.frame(list(Species = remove_NCBInums(N_unique), Unique = "N"))
unique <- rbind(S1, S2, N)

S1_i <- data.frame(list(Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_S1]), Indicator = "S1"))
S2_i <- data.frame(list(Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_S2]), Indicator = "S2"))
N_i <- data.frame(list(Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_N]), Indicator = "N"))
indicators <- rbind(S1_i, S2_i, N_i)

df_list <- list(unique, indicators)
full_taxa_list <- df_list %>% reduce(full_join, by = "Species")





synonyms <- c()
for (s in full_taxa_list$Species) {
  print(s)
  worms_ID <- get_wormsid(s)
  if (is.na(worms_ID)) {
    syns <- NA
  } else {
    syns <- synonyms(worms_ID, db = "worms")
    syns <- toString(syns[[1]]$scientificname)
  }
  synonyms <- rbind(synonyms, syns)
}


full_taxa_list <- cbind(full_taxa_list, synonyms)

# Remove anything in parentheticals
full_taxa_list$synonyms <- gsub("\\s*\\([^\\)]+\\)", "", full_taxa_list$synonyms)

# Remove anything beyond two words in each comma separated section
for (syn in 1:length(full_taxa_list$synonyms)) {
  print(syn)
  all <- unlist(strsplit(full_taxa_list$synonyms[syn], ","))
  if (!is.na(all[1])) {
    print(all)
    for (i in 1:length(all)) {
      print(all[i])
      all[i] <- str_trim(all[i])
      all[i] <- sub("^(\\S*\\s+\\S+).*", "\\1", all[i])
      print(all[i])
    }
  }
  syns <- toString(unique(all))
  full_taxa_list$synonyms[syn] <- syns
}


write.csv(full_taxa_list, "Analysis Products/BPT_Analysis.csv", row.names = FALSE)


# Read in needed text of Between Pacific Tides (file not given on GitHub due to copyright)
txt <- pdf_text("Data/BetweenPacificTides_TextForSearching.pdf")
toc <- pdf_text("Data/BetweenPacificTides_TOC.pdf")

# first remove hyphenated situations "-\n"
# then remove all line breaks "\n"
txt <- gsub("-\n", "", txt)
txt <- gsub("\n", " ", txt)

# Clean up TOC
toc <- strsplit(toc, "\n")
toc <- c(toc[[1]], toc[[2]], toc[[3]])
page_nums <- grepl("[1234567890,]$", toc)
toc <- toc[page_nums]

# Fix the couple of strings that are split over multiple lines
toc_cleaned <- c(toc[1:14], paste0(toc[15], toc[16]), toc[17:21], paste0(toc[22], toc[23]), toc[24:53])
toc_cleaned <- as.data.frame(toc_cleaned)
toc_cleaned <- extract(toc_cleaned, toc_cleaned, into = c("text", "page"), "(.*)\\s+([^ ]+)$")
toc_cleaned$page <- as.numeric(toc_cleaned$page)


toc_cleaned_max <- vector()
for (x in 1:(nrow(toc_cleaned) - 1)) {
  print(x)
  if (toc_cleaned$page[x] == toc_cleaned$page[x + 1]) {
    toc_cleaned_max[x] <- toc_cleaned$page[x]
  } else {
    toc_cleaned_max[x] <- toc_cleaned$page[x + 1] - 1
  }
}
toc_cleaned_max[nrow(toc_cleaned)] <- NA

toc_cleaned$max_page <- toc_cleaned_max

# remove everything not referring to rocky shores
toc_cleaned <- toc_cleaned[1:17, ]

# Remove just rows with zone
toc_zones <- toc_cleaned %>% filter(grepl("Zone", text))
toc_zones$text <- gsub("\\..*", "", toc_zones$text)
toc_zones$text <- trimws(toc_zones$text)


output <- c()
for (x in 1:length(full_taxa_list$Species)) {
  species <- full_taxa_list$Species[x]
  synonyms <- full_taxa_list$synonyms[x]
  synonyms <- unlist(strsplit(synonyms, ", "))
  all <- c(species, synonyms)
  all_abbreviated <- sub("[a-z]* ", ". ", all)
  all_to_search <- c(all, all_abbreviated)

  all_pages <- vector()
  for (y in all_to_search) {
    print(y)
    pages <- grep(y, txt, ignore.case = FALSE, fixed = TRUE)
    all_pages <- c(all_pages, pages)
    print(pages)
  }
  all_pages <- unique(all_pages)
  output[x] <- list(all_pages)
}

full_taxa_list$pages <- output
full_taxa_list$pages[sapply(full_taxa_list$pages, function(x) length(x) == 0)] <- NA



zones <- unique(toc_zones$text)
df <- data.frame(matrix(ncol = length(zones), nrow = 0))
colnames(df) <- zones

name <- c()
zone <- c()
page <- c()

for (x in 1:length(full_taxa_list$pages)) {
  list <- full_taxa_list$pages[[x]]
  if (!is.na(list[1])) {
    for (y in 1:length(list)) {
      num <- list[y]
      for (z in 1:length(toc_zones$text)) {
        min <- toc_zones$page[z]
        max <- toc_zones$max[z]
        if (num <= max && num >= min) {
          name <- append(name, full_taxa_list$Species[x])
          zone <- append(zone, toc_zones$text[z])
          page <- append(page, num)
        } else {
        }
      }
    }
  }
}

final_1 <- as.data.frame(cbind(name, zone, page))

# Split "Zones 1 and 2" into two entries
to_split <- final_1 %>%
  filter(zone == "Zones 1 and 2") %>%
  mutate(zone = "Zone 1")
final_2 <- final_1 %>% mutate(zone = replace(zone, zone == "Zones 1 and 2", "Zone 2"))
final_2 <- rbind(final_2, to_split)


# Split "Zones 2 and 3" into two entries
to_split <- final_1 %>%
  filter(zone == "Zones 2 and 3") %>%
  mutate(zone = "Zone 2")
final_2 <- final_2 %>% mutate(zone = replace(zone, zone == "Zones 2 and 3", "Zone 3"))
final_2 <- rbind(final_2, to_split)


condense <- final_2 %>% pivot_wider(names_from = zone, values_from = page, values_fn = unique(list()))


condense <- left_join(condense, full_taxa_list[, c("Species", "Unique", "Indicator")], by = join_by(name == Species))

condense <- condense %>% mutate(Site = coalesce(Unique, Indicator))
condense <- condense %>% relocate(Site, Unique, Indicator, name, "Zone 4", "Zone 3", "Zone 2", "Zone 1")

condense <- condense %>% rename(Zone_1 = "Zone 1", Zone_2 = "Zone 2", Zone_3 = "Zone 3", Zone_4 = "Zone 4")



condense_no_pages <- condense
condense_no_pages$Zone_1 <- !sapply(condense_no_pages$Zone_1, is.null)
condense_no_pages$Zone_2 <- !sapply(condense_no_pages$Zone_2, is.null)
condense_no_pages$Zone_3 <- !sapply(condense_no_pages$Zone_3, is.null)
condense_no_pages$Zone_4 <- !sapply(condense_no_pages$Zone_4, is.null)


# Adjust Based on Manual Checking

# remove "Proboscidactyla flavicirrata" because search identified the wrong abbreviated synonym
condense_no_pages <- condense_no_pages %>% filter(name != "Proboscidactyla flavicirrata")

# add "Laminaria setchellii" because it was found manually and only appears in a diagram (so not in text search)
condense_no_pages <- condense_no_pages %>% add_row(Site = "N", Unique = "N", Indicator = NA, name = "Laminaria setchellii", Zone_4 = TRUE, Zone_3 = FALSE, Zone_2 = FALSE, Zone_1 = FALSE)

# add "Egregia menziesii" because it was found manually through the index, but only appears by genus in the text
condense_no_pages <- condense_no_pages %>% add_row(Site = "S2", Unique = "S2", Indicator = NA, name = "Egregia menziesii", Zone_4 = TRUE, Zone_3 = TRUE, Zone_2 = TRUE, Zone_1 = FALSE)

# add "Pandalus danae" because it was found manually through the index, but only appears by genus in the text
condense_no_pages <- condense_no_pages %>% add_row(Site = "S2", Unique = "S2", Indicator = NA, name = "Pandalus danae", Zone_4 = TRUE, Zone_3 = FALSE, Zone_2 = FALSE, Zone_1 = FALSE)

# Adjust "Ectopleura marina" to include Zone_3 (found manually because mentioned on that page with genus only, but linked in the index)
condense_no_pages <- condense_no_pages %>% mutate(Zone_3 = replace(Zone_3, name == "Ectopleura marina", TRUE))

# Adjust "Halosydna brevisetosa" to include Zone_4 (found manually because mentioned on that page with genus only, but linked in the index)
condense_no_pages <- condense_no_pages %>% mutate(Zone_4 = replace(Zone_4, name == "Halosydna brevisetosa", TRUE))



condense_no_pages <- condense_no_pages %>% arrange(name)
condense_no_pages <- condense_no_pages %>% arrange(desc(Zone_1), desc(Zone_2), desc(Zone_3), desc(Zone_4))
condense_no_pages <- condense_no_pages %>% arrange(factor(Site, levels = c("S1", "S2", "N")))







contingency_table <- condense_no_pages %>%
  group_by(Site) %>%
  summarise(High = sum(Zone_1 == TRUE | Zone_2 == TRUE | Zone_3 == TRUE), Low = sum(Zone_1 == FALSE & Zone_2 == FALSE & Zone_3 == FALSE))
contingency_table <- contingency_table %>%
  select(-Site) %>%
  as.matrix()
rownames(contingency_table) <- c("N", "S1", "S2")


set.seed(1)

test <- chisq.test(contingency_table, correct = FALSE, simulate.p.value = TRUE)

test_post_hoc <- chisq.posthoc.test(contingency_table, method = "bonferroni", simulate.p.value = TRUE)


for_plotting <- condense_no_pages
for_plotting <- for_plotting %>% mutate(Unique = replace(Unique, !is.na(Unique), "X"), Unique = replace(Unique, is.na(Unique), ""), Indicator = replace(Indicator, !is.na(Indicator), "X"), Indicator = replace(Indicator, is.na(Indicator), ""))




for_plotting <- for_plotting %>%
  gt(groupname_col = "Site", id = "mygt") %>%
  tab_spanner(
    label = "Intertidal Zones",
    columns = c(
      Zone_4, Zone_3, Zone_2, Zone_1
    )
  ) %>%
  tab_options(row_group.as_column = TRUE) %>%
  gt_color_rows("Zone_4", palette = c("white", "#D1E7C7")) %>%
  gt_color_rows("Zone_3", palette = c("white", "#BBBED1")) %>%
  gt_color_rows("Zone_2", palette = c("white", "#BBBED1")) %>%
  gt_color_rows("Zone_1", palette = c("white", "#BBBED1")) %>%
  tab_style(
    style = cell_text(style = "italic"),
    locations = cells_body(
      columns = name
    )
  ) %>%
  tab_style(
    style = cell_text(color = "#FFFFFF00", size = "x-small"),
    locations = cells_body(
      columns = c("Zone_4", "Zone_3", "Zone_2", "Zone_1")
    )
  ) %>%
  tab_style(
    style = cell_text(size = px(12)),
    locations = cells_body(
      columns = c("Unique", "Indicator", "name")
    )
  ) %>%
  cols_align(
    align = "center",
    columns = c("Unique", "Indicator")
  ) %>%
  cols_label(
    Zone_1 = "1",
    Zone_2 = "2",
    Zone_3 = "3",
    Zone_4 = "4",
    name = "Species",
    Unique = "Uniq.\nTo",
    Indicator = "Indic.\nOf"
  ) %>%
  tab_style(
    style = cell_text(v_align = "middle"),
    locations = cells_row_groups()
  ) %>%
  tab_style(
    style = cell_borders(
      sides = c("bottom"),
      color = "black",
      weight = px(3)
    ),
    locations = list(cells_column_spanners(), cells_column_labels())
  ) %>%
  tab_style(
    style = cell_borders(
      sides = "all",
      color = "black",
      weight = px(3)
    ),
    locations = list(cells_row_groups())
  ) %>%
  tab_style(
    style = cell_borders(
      sides = "all",
      color = "black"
    ),
    locations = cells_body()
  ) %>%
  tab_style(
    style = cell_borders(
      sides = "bottom",
      color = "black",
      weight = px(3)
    ),
    locations = cells_body(rows = c(18, 31, 41))
  ) %>%
  tab_style(
    style = cell_borders(
      sides = "right",
      color = "black",
      weight = px(3)
    ),
    locations = cells_body(columns = 8)
  ) %>%
  tab_options(data_row.padding = px(1)) %>%
  data_color(
    columns = Unique,
    rows = Unique == "X",
    palette = "lightgray",
  ) %>%
  data_color(
    columns = Indicator,
    rows = Indicator == "X",
    palette = "lightgray",
  ) %>%
  tab_options(
    table.border.top.style = "hidden"
  ) %>%
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_column_labels(columns = name)
  )



path <- "Figures/Figure9.png"
gtsave(for_plotting, filename = path)

Identified unique and indicator taxa reflected known ecological differences between locations. Only a subset of unique and indicator taxa were described in Between Pacific Tides: 18.8% (9/48) of nearshore taxa, 32.1% (17/53) of S1 taxa, and 31.1% (14/45) of S2. However, across the described subset, more taxa from S1 were categorized to high and middle intertidal zones than S2 and N (Figure 9; not made in R). The proportion of taxa from the high and middle intertidal varied significantly across locations (χ2 =11.67, p<0.05), matching the environmental characteristics of the sites.

Figure 9: Chart habitat information about unique and indicator species present in Between Pacific Tides
Figure 9: Chart habitat information about unique and indicator species present in Between Pacific Tides

Supporting Information

### Supporting Figure 1###

path <- "Figures/FigureS1."
save_pdf_png(plot = heatmap_ASV$plot, path = path, w = 169, h = 300, u = "mm", bg = "transparent", dpi = 600)
Figure S1: Heat map of identified indicator ASVs for all three locations over time, scaled by the number of replicates that detected that species.
Figure S1: Heat map of identified indicator ASVs for all three locations over time, scaled by the number of replicates that detected that species.
## Supporting Table 1###

overlap_table
write.csv(overlap_table, "Analysis Products/TableS1.csv", row.names = FALSE)

By analyzing occurrence data from the Global Biodiversity Information Facility (on 2023-12-15 Sys.Date()), we confirmed that 100 percentages$count[6] of r sum(percentages$count)``sum(percentages$count) identified species (24.1% sprintf("%0.1f%%", percentages$per[6] * 100)) have occurrence records at Pillar Point, specifically. An additional 193 percentages$count[5] identified species (46.5% sprintf("%0.1f%%", percentages$per[5] * 100)) have occurrence records in the California Current System (CCS) and known ranges that encompass Pillar Point. Of the remaining species, some only fulfilled one of two criteria; 11 percentages$count[4] identified species (2.7% sprintf("%0.1f%%", percentages$per[4] * 100)) had occurrence records in the CCS but known ranges that did not encompass Pillar Point and 37 percentages$count[3] identified species (8.9% sprintf("%0.1f%%", percentages$per[3] * 100)) had ranges that encompass Pillar Point but no occurrence records in the CCS. Additionally, 39 percentages$count[1] identified species (9.4% sprintf("%0.1f%%", percentages$per[1] * 100)) had neither occurrence records in the CCS nor known ranges that encompassed Pillar Point. Finally, 15 percentages$count[2] identified species (3.6% sprintf("%0.1f%%", percentages$per[2] * 100)) lacked sufficient occurrence records in GBIF to make any designation, and 20 percentages$count[7] identified species (4.8% sprintf("%0.1f%%", percentages$per[7] * 100)) did not have species-level records in GBIF. Full details by species can be found in Table S2.

## Supporting Table 2###

GBIF_summary
write.csv(GBIF_summary, "Analysis Products/TableS2.csv", row.names = TRUE)

Code for Making Versions of Figures for PowerPoint

Figure 3

### Version of Figure 3 optimized for PowerPoint slides/animations###

graph <- sample_schema

if (!dir.exists("Figures/PowerPoint")) {
  dir.create("Figures/PowerPoint", recursive = TRUE)
}

filename <- paste0("sample_schema_full.pdf")
path <- paste0("Figures/PowerPoint/", filename)
pdf(path, width = 13, height = 4.3)
print(graph)
dev.off()

graph$layers[[1]] <- NULL

alpha <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

for (i in 1:12) {
  alpha[i] <- 1
  graph <- graph +
    scale_color_viridis_d(direction = -1, alpha = alpha) +
    scale_fill_viridis_d(direction = -1, alpha = alpha)
  filename <- paste0("sample_schema", i, ".pdf")
  path <- paste0("Figures/PowerPoint/", filename)
  pdf(path, width = 13, height = 4.3)
  print(graph)
  dev.off()
}

Figure 4

### Version of Figure 4 optimized for PowerPoint slides/animations###

p <- ggtree::ggtree(pt_physeq, layout = "rectangular")

ordered_names <- ggtree::get_taxa_name(p)
ordered_names <- unique(ordered_names)
ordered_names[match(rownames(tax_table(pt_physeq)), ordered_names)] <- tax_table(pt_physeq)[, "Phylum"]
ordered_names <- unique(ordered_names)

names(colors_ordered) <- ordered_names

p <- p + geom_fruit(geom = geom_tile, mapping = aes(fill = Phylum), width = 3, show.legend = FALSE) + scale_fill_manual(values = colors_ordered) + scale_color_manual(values = colors_ordered)

p <- p + ggtree::geom_hilight(data = phyla_nodes, mapping = aes(node = node, fill = node_phylum), show.legend = FALSE)

p <- p +
  theme(
    panel.background = element_rect(fill = "transparent"),
    plot.background = element_rect(fill = "transparent", color = NA),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    legend.background = element_rect(fill = "transparent"),
    legend.box.background = element_rect(fill = "transparent")
  )

ggsave(
  "Figures/PowerPoint/phylo.pdf",
  plot = p,
  width = 4.49,
  height = 7.06,
  dpi = 300,
  bg = "transparent"
)

Figure 6

### Version of Figure 6 optimized for PowerPoint slides/animations###

graph <- heatmap_taxa$plot

path <- "Figures/PowerPoint/indicator_figure.png"
ggsave(filename = path, plot = graph, width = 13, height = 6.69)

Figure 7

### Version of Figure 7 optimized for PowerPoint slides/animations###

alpha <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
graph <- NMDS_PAM_full$NMDS +
  ggtitle("NMDS Ordination (Jaccard Dissimilarity)") +
  theme_classic(base_size = 18)

filename <- paste("NMDS_figure_full.pdf")
path <- paste("Figures/PowerPoint/", filename)
pdf(path, width = 11.97, height = 6.14)
print(graph)
dev.off()

graph$layers[[2]] <- NULL

graph <- graph +
  stat_ellipse(aes(group = Location), type = "t", linetype = 2, alpha = 0)

for (i in 1:12) {
  alpha[i] <- 1
  graph <- graph +
    viridis::scale_color_viridis(
      discrete = TRUE,
      begin = 0,
      end = .97,
      direction = -1,
      alpha = alpha
    )
  filename <- paste("NMDS_figure", i, ".pdf")
  path <- paste("Figures/PowerPoint/", filename)
  pdf(path, width = 11.97, height = 6.14)
  print(graph)
  dev.off()
  alpha[i] <- .2
}

Session Info

sessionInfo()
## R version 4.3.1 (2023-06-16)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Ventura 13.0.1
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices datasets  utils     methods  
## [8] base     
## 
## other attached packages:
##  [1] gtExtras_0.5.0           gt_0.10.0                pdftools_3.4.0          
##  [4] ampvis2_2.8.6            ggtreeExtra_1.12.0       ggtree_3.10.0           
##  [7] phyloseq_1.46.0          styler_1.10.2            devtools_2.4.5          
## [10] usethis_2.2.2            chunkhooks_0.0.1         ggh4x_0.2.6             
## [13] ggbeeswarm_0.7.2         mapview_2.11.2           rgbif_3.7.8             
## [16] mregions_0.1.8           spocc_1.2.2              pals_1.8                
## [19] Polychrome_1.5.1         taxize_0.9.100           chisq.posthoc.test_0.1.2
## [22] vegan_2.6-4              lattice_0.22-5           cluster_2.1.6           
## [25] indicspecies_1.7.14      permute_0.9-7            eulerr_7.0.0            
## [28] patchwork_1.1.3          sf_1.0-14                lubridate_1.9.3         
## [31] forcats_1.0.0            stringr_1.5.1            dplyr_1.1.4             
## [34] purrr_1.0.2              readr_2.1.4              tidyr_1.3.0             
## [37] tibble_3.2.1             ggplot2_3.4.4            tidyverse_2.0.0         
## 
## loaded via a namespace (and not attached):
##   [1] fs_1.6.3                bitops_1.0-7            bold_1.3.0             
##   [4] fontawesome_0.5.2       oai_0.4.0               httr_1.4.7             
##   [7] RColorBrewer_1.1-3      worrms_0.4.3            profvis_0.3.8          
##  [10] tools_4.3.1             utf8_1.2.4              R6_2.5.1               
##  [13] lazyeval_0.2.2          mgcv_1.9-0              measurements_1.5.1     
##  [16] rhdf5filters_1.14.1     urlchecker_1.0.1        withr_2.5.2            
##  [19] sp_2.1-2                gridExtra_2.3           prettyunits_1.2.0      
##  [22] leaflet_2.2.1           textshaping_0.3.7       leafem_0.2.3           
##  [25] cli_3.6.1               Biobase_2.62.0          labeling_0.4.3         
##  [28] sass_0.4.8              proxy_0.4-27            askpass_1.2.0          
##  [31] systemfonts_1.0.5       yulab.utils_0.1.0       R.utils_2.12.3         
##  [34] dichromat_2.0-0.1       sessioninfo_1.2.2       maps_3.4.1.1           
##  [37] rstudioapi_0.15.0       httpcode_0.3.0          generics_0.1.3         
##  [40] gridGraphics_0.5-1      crosstalk_1.2.1         Matrix_1.6-4           
##  [43] biomformat_1.30.0       fansi_1.0.5             S4Vectors_0.40.2       
##  [46] R.methodsS3_1.8.2       terra_1.7-55            lifecycle_1.0.4        
##  [49] whisker_0.4.1           scatterplot3d_0.3-44    yaml_2.3.7             
##  [52] rvertnet_0.8.2          rhdf5_2.46.1            paletteer_1.5.0        
##  [55] promises_1.2.1          crayon_1.5.2            miniUI_0.1.1.1         
##  [58] conditionz_0.1.0        chromote_0.1.2          geojson_0.3.5          
##  [61] mapproj_1.2.11          pillar_1.9.0            knitr_1.45             
##  [64] codetools_0.2-19        fastmatch_1.1-4         wk_0.9.1               
##  [67] glue_1.6.2              rebird_1.3.0            V8_4.4.1               
##  [70] ggfun_0.1.3             qpdf_1.3.2              data.table_1.14.8      
##  [73] remotes_2.4.2.1         urltools_1.7.3          vctrs_0.6.5            
##  [76] png_0.1-8               treeio_1.26.0           gtable_0.3.4           
##  [79] assertthat_0.2.1        rematch2_2.1.2          cachem_1.0.8           
##  [82] xfun_0.41               mime_0.12               survival_3.5-7         
##  [85] iterators_1.0.14        units_0.8-5             ellipsis_0.3.2         
##  [88] nlme_3.1-164            satellite_1.0.4         GenomeInfoDb_1.38.1    
##  [91] R.cache_0.16.0          bslib_0.6.1             vipor_0.4.5            
##  [94] KernSmooth_2.23-22      colorspace_2.1-0        BiocGenerics_0.48.1    
##  [97] DBI_1.1.3               raster_3.6-26           ade4_1.7-22            
## [100] phangorn_2.11.1         tidyselect_1.2.0        processx_3.8.2         
## [103] compiler_4.3.1          curl_5.1.0              geojsonsf_2.0.3        
## [106] xml2_1.3.6              plotly_4.10.3           triebeard_0.4.1        
## [109] scales_1.3.0            classInt_0.4-10         quadprog_1.5-8         
## [112] callr_3.7.3             digest_0.6.33           rmarkdown_2.25         
## [115] XVector_0.42.0          htmltools_0.5.7         pkgconfig_2.0.3        
## [118] base64enc_0.1-3         highr_0.10              fastmap_1.1.1          
## [121] rlang_1.1.2             htmlwidgets_1.6.4       shiny_1.8.0            
## [124] farver_2.1.1            jquerylib_0.1.4         zoo_1.8-12             
## [127] jsonlite_1.8.8          R.oo_1.25.0             RCurl_1.98-1.13        
## [130] magrittr_2.0.3          GenomeInfoDbData_1.2.11 ggplotify_0.1.2        
## [133] s2_1.1.4                Rhdf5lib_1.24.0         munsell_0.5.0          
## [136] Rcpp_1.0.11             viridis_0.6.4           ape_5.7-1              
## [139] ggnewscale_0.4.9        stringi_1.8.2           zlibbioc_1.48.0        
## [142] MASS_7.3-60             jqr_1.3.3               plyr_1.8.9             
## [145] pkgbuild_1.4.2          parallel_4.3.1          ggrepel_0.9.4          
## [148] geojsonio_0.11.3        Biostrings_2.70.1       splines_4.3.1          
## [151] multtest_2.58.0         hms_1.1.3               polylabelr_0.2.0       
## [154] ps_1.7.5                igraph_1.5.1            uuid_1.1-1             
## [157] reshape2_1.4.4          stats4_4.3.1            pkgload_1.3.3          
## [160] crul_1.4.0              ridigbio_0.3.7          evaluate_0.23          
## [163] leaflet.providers_2.0.0 renv_1.0.3              BiocManager_1.30.22    
## [166] tzdb_0.4.0              foreach_1.5.2           httpuv_1.6.13          
## [169] webshot2_0.1.1          polyclip_1.10-6         xtable_1.8-4           
## [172] e1071_1.7-14            tidytree_0.4.5          later_1.3.2            
## [175] viridisLite_0.4.2       class_7.3-22            ragg_1.2.6             
## [178] websocket_1.4.1         aplot_0.2.2             memoise_2.0.1          
## [181] beeswarm_0.4.0          IRanges_2.36.0          timechange_0.2.0
LS0tCnRpdGxlOiAiRW52aXJvbm1lbnRhbCBETkEgKGVETkEpIG1ldGFiYXJjb2RpbmcgZGlmZmVyZW50aWF0ZXMgYmV0d2VlbiBtaWNyby1oYWJpdGF0cyB3aXRoaW4gdGhlIHJvY2t5IGludGVydGlkYWwiCmF1dGhvcjogIk1lZ2hhbiBNLiBTaGVhIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKLS0tCgpgYGB7ciwgc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgdGlkeSA9ICJzdHlsZXIiKQpgYGAKCmBgYHtyLCBMb2FkaW5nIFBhY2thZ2VzLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQojIyNMb2FkaW5nIFBhY2thZ2VzIyMjCgpyZW52OjpyZXN0b3JlKCkKCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsIAogICAgICAgICAgICAgICJzZiIsCiAgICAgICAgICAgICAgInBhdGNod29yayIsIAogICAgICAgICAgICAgICJzdHJpbmdyIiwgCiAgICAgICAgICAgICAgImV1bGVyciIsIAogICAgICAgICAgICAgICJpbmRpY3NwZWNpZXMiLCAKICAgICAgICAgICAgICAiY2x1c3RlciIsCiAgICAgICAgICAgICAgInZlZ2FuIiwKICAgICAgICAgICAgICAiY2hpc3EucG9zdGhvYy50ZXN0IiwgCiAgICAgICAgICAgICAgInRheGl6ZSIsCiAgICAgICAgICAgICAgIlBvbHljaHJvbWUiLAogICAgICAgICAgICAgICJwYWxzIiwgCiAgICAgICAgICAgICAgInNwb2NjIiwKICAgICAgICAgICAgICAibXJlZ2lvbnMiLAogICAgICAgICAgICAgICJyZ2JpZiIsCiAgICAgICAgICAgICAgIm1hcHZpZXciLAogICAgICAgICAgICAgICJnZ2JlZXN3YXJtIiwKICAgICAgICAgICAgICAiZ2doNHgiLAogICAgICAgICAgICAgICJjaHVua2hvb2tzIiwKICAgICAgICAgICAgICAiZGV2dG9vbHMiLCAKICAgICAgICAgICAgICAiZ3JpZCIsCiAgICAgICAgICAgICAgInN0eWxlciIsCiAgICAgICAgICAgICAgInBoeWxvc2VxIiwKICAgICAgICAgICAgICAiZ2d0cmVlIiwKICAgICAgICAgICAgICAiZ2d0cmVlRXh0cmEiLAogICAgICAgICAgICAgICJhbXB2aXMyIiwKICAgICAgICAgICAgICAicGRmdG9vbHMiLAogICAgICAgICAgICAgICJndCIsCiAgICAgICAgICAgICAgImd0RXh0cmFzIikKCmludmlzaWJsZShsYXBwbHkocGFja2FnZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpCiAgICAgICAgICAgICAgCmhvb2tfZmlndXJlX3VuaXQoKQpgYGAKCmBgYHtyLCBDb3JlIEZ1bmN0aW9uc30KIyMjQ29yZSBGdW5jdGlvbnMjIyMKI0NvbGxlY3Rpb24gb2YgZnVuY3Rpb25zIHVzZWQgYWNyb3NzIGFuYWx5c2VzCgojRnVuY3Rpb24gdGhhdCByZW1vdmVzIE5DQkkgVGF4b25vbXkgSURzIGZyb20gdGhlIGVuZCBvZiB0YXhvbm9taWMgbmFtZXMgKGFzIGluIHRoZSBBbmFjYXBhIFBpcGVsaW5lIG91dHB1dCkgCnJlbW92ZV9OQ0JJbnVtcyA9IGZ1bmN0aW9uKGxpc3QpIHsKICBsaXN0ID0gc3ViKCJfW15fXSskIiwiIiwgbGlzdCkKICByZXR1cm4obGlzdCkKfQoKI0Z1bmN0aW9uIHRoYXQgY29udmVydHMgYW4gYW1wdmlzMiBvYmplY3QgdG8gYSBwaHlsb3NlcSBvYmplY3QKI0NhbiBiZSB1c2VkIGVpdGhlciBvbiBhbiBleGlzdGluZyBhbXB2aXMyIG9iamVjdCAoYWJ1bmQsIHRheCwgbWQgPSBOVUxMKSBvciBzZXBhcmF0ZSBhYnVuZCwgdGF4LCBhbmQgbWV0YWRhdGEgZGF0YSBmcmFtZXMgKGFtcHZpcyA9IE5VTEwpCmFtcF90b19waHlsb3NlcSA9IGZ1bmN0aW9uKGFtcHZpcywgYWJ1bmQsIHRheCwgbWQpIHsKICBpZighaXMubnVsbChhbXB2aXMpKSB7CiAgICBwaHlzZXEgPSBwaHlsb3NlcShvdHVfdGFibGUoYXMubWF0cml4KGFtcHZpcyRhYnVuZCksIHRheGFfYXJlX3Jvd3MgPSBUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgdGF4X3RhYmxlKGFzLm1hdHJpeChhbXB2aXMkdGF4KSksIAogICAgICAgICAgICAgICAgICAgIHNhbXBsZV9kYXRhKGFtcHZpcyRtZXRhZGF0YSkpCiAgfSBlbHNlIGlmIChpcy5udWxsKG1kKSkgewogICAgcGh5c2VxID0gcGh5bG9zZXEob3R1X3RhYmxlKGFzLm1hdHJpeChhYnVuZCksIHRheGFfYXJlX3Jvd3MgPSBUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgdGF4X3RhYmxlKGFzLm1hdHJpeCh0YXgpKSkKfSBlbHNlIHsKICBwaHlzZXEgPSBwaHlsb3NlcShvdHVfdGFibGUoYXMubWF0cml4KGFidW5kKSwgdGF4YV9hcmVfcm93cyA9IFRSVUUpLCAKICAgICAgICAgICAgICAgICAgICB0YXhfdGFibGUoYXMubWF0cml4KHRheCkpLCAKICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShtZCkpCn0KICByZXR1cm4ocGh5c2VxKQp9CgojRnVuY3Rpb24gdGhhdCBzYXZlcyAucG5nIGFuZCAucGRmIHZlcnNpb25zIG9mIGEgZ2l2ZW4gZmlndXJlCnNhdmVfcGRmX3BuZyA9IGZ1bmN0aW9uKHBsb3QsIHBhdGgsIHcsIGgsIHUsIGJnLCBkcGkpIHsKICBmb3IoeCBpbiBjKCJwZGYiLCAicG5nIikpIHsKICAgIGdnc2F2ZSgKICAgICAgcGxvdCA9IHBsb3QsCiAgICAgIGZpbGVuYW1lID0gcGFzdGUwKHBhdGgsIHgpLAogICAgICBkZXZpY2UgPSB4LAogICAgICBiZyA9IGJnLAogICAgICB3aWR0aCA9IHcsCiAgICAgIGhlaWdodCA9IGgsCiAgICAgIHVuaXRzID0gdSwgCiAgICAgIGRwaSA9IGRwaQogICkKICB9Cn0KYGBgCgojIyMgTWF0ZXJpYWxzIGFuZCBNZXRob2RzCgojIyMjIDIuMSBEZXRhaWxlZCBQcm90b2NvbHMKClRvIGltcHJvdmUgcmVwcm9kdWNpYmlsaXR5IChlLmcuIERpY2tpZSBldCBhbC4sIDIwMTg7IFNoZWEgZXQgYWwuLCAyMDIzKSwgZW5hYmxlIG9wZW4gZGF0YSBzY2llbmNlIChlLmcuIEZyZWRzdG9uIGFuZCBMb3duZGVzLCAyMDI0KSwgYW5kIGFpZCBpbiB0aGUgaW5pdGlhdGlvbiBvZiBuZXcgZUROQSBiaW9tb25pdG9yaW5nIHByb2plY3RzLCB3ZSBoYXZlIHB1Ymxpc2hlZCBkZXRhaWxlZCwgc3RlcC1ieS1zdGVwIHByb3RvY29scyBmb3IgbWFueSBvZiB0aGUgbWV0aG9kcyBkZXNjcmliZWQsIGluY2x1ZGluZyBzcGVjaWZpYyBtYXRlcmlhbHMgdXNlZCwgcGhvdG9ncmFwaHMsIGFuZCBhZGRpdGlvbmFsIG1ldGhvZG9sb2dpY2FsIG5vdGVzIG5vdCBwb3NzaWJsZSB0byBpbmNsdWRlIGhlcmUuIFNlZSBTaGVhICgyMDIzKSBmb3Igc2FtcGxlIGNvbGxlY3Rpb24gYW5kIGZpbHRlcmluZywgU2hlYSAoMjAyMykgZm9yIEROQSBleHRyYWN0aW9ucywgU2hlYSAoMjAyMykgZm9yIFBDUiBhbXBsaWZpY2F0aW9uLCBhbmQgU2hlYSAoMjAyMykgZm9yIHNoaXBwaW5nIHNhbXBsZXMuIEFkZGl0aW9uYWxseSwgd2UgaGF2ZSBwdWJsaXNoZWQgYWxsIGRhdGEgYW5kIGNvZGUgZm9yIHJlcGxpY2F0aW5nIG91ciBhbmFseXNlcyB2aWEgRHJ5YWQsIGluY2x1ZGluZyBGQVNUUSBmaWxlcywgb3VyIG1vZGlmaWVkIEFuYWNhcGEgQ29udGFpbmVyIGFuZCBzY3JpcHRzIGZvciBiaW9pbmZvcm1hdGljcywgdW5wcm9jZXNzZWQgYW5kIHByb2Nlc3NlZCBkYXRhc2V0cywgYW5kIGFuIFIgTWFya2Rvd24gZmlsZSB0aGF0IHJlcHJvZHVjZXMgYWxsIG1ldGhvZHMgJiByZXN1bHRzIGRldGFpbGVkIGhlcmUgKERyeWFkIGNpdGF0aW9uKS4KCiMjIyMgMi4yIFNhbXBsaW5nIFNpdGUKClRvIGJldHRlciB1bmRlcnN0YW5kIHNwYXRpYWwgYW5kIHRlbXBvcmFsIGRpZmZlcmVuY2VzIGluIGVETkEgc2lnbmFscyBpbiBhIGNvbXBsZXggY29hc3RhbCBlbnZpcm9ubWVudCwgd2Ugc291Z2h0IGEgcm9ja3kgaW50ZXJ0aWRhbCBmaWVsZCBsb2NhdGlvbiB0aGF0IGhhZCBjb25zaXN0ZW50LCBsYXJnZSwgYWNjZXNzaWJsZSB0aWRlIHBvb2xzIHRoYXQgd2VyZSBmdWxseSBpc29sYXRlZCBmcm9tIG9uZSBhbm90aGVyIGF0IHNvbWUgbG93IHRpZGVzIGJ1dCBpbnRlcmNvbm5lY3RlZCBkdXJpbmcgb3RoZXIgcGFydHMgb2YgdGhlaXIgZXhwb3N1cmUgcGVyaW9kLiBXZSBzZWxlY3RlZCB0aGUgaW50ZXJ0aWRhbCBhdCBQaWxsYXIgUG9pbnQsIGEgaGVhZGxhbmRzIHByb21vbnRvcnkgdG8gdGhlIHdlc3Qgb2YgUGlsbGFyIFBvaW50IEhhcmJvciBpbiBTYW4gTWF0ZW8gQ291bnR5LCBDYWxpZm9ybmlhLCBVU0EuIFBpbGxhciBQb2ludCBpcyBhIHBvcHVsYXIgcmVjcmVhdGlvbmFsIGludGVydGlkYWwgc2l0ZSB0aGF0IGlzIGRpcmVjdGx5IGFkamFjZW50IHRvIHRoZSBQaWxsYXIgUG9pbnQgU3RhdGUgTWFyaW5lIENvbnNlcnZhdGlvbiBBcmVhIChubyBzcGVjaWZpYyB1c2Ugc2NpZW50aWZpYyBjb2xsZWN0aW9uIHBlcm1pdCByZXF1aXJlZCkuCgpXaXRoaW4gUGlsbGFyIFBvaW50LCB3ZSBzYW1wbGVkIGF0IHRocmVlIGRpc2NyZXRlIGxvY2F0aW9uczogdHdvIGluZGl2aWR1YWwgdGlkZSBwb29scyB3aXRoIGEgcmFuZ2Ugb2YgcGh5c2ljYWwgY29ubmVjdGl2aXR5IChUaWRlIFBvb2wgMSwgUzE6IDM3LjQ5NTM0MsKwLCAtMTIyLjQ5ODczMcKwOyBUaWRlIFBvb2wgMiwgUzI6IDM3LjQ5NTAwMMKwLCAtMTIyLjQ5ODk0N8KwKSBhbmQgYW4gZXF1aWRpc3RhbnQgbG9jYXRpb24gKE5lYXJzaG9yZSwgTjogMzcuNDk1MjgzM8KwLCAtMTIyLjQ5OTIwNTbCsCkgd2hlcmUgdGhlcmUgd2FzIHdlbGwtbWl4ZWQgb2Zmc2hvcmUgd2F0ZXIgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgdGlkYWwgY3ljbGUgKEZpZ3VyZSAyOyBub3QgcHJvZHVjZWQgaW4gUikuIEVhY2ggc2l0ZSB3YXMgYXBwcm94aW1hdGVseSA0MCBtZXRlcnMgZnJvbSBhbGwgb3RoZXIgc2l0ZXMuIFRpZGUgUG9vbCAxIGFuZCBUaWRlIFBvb2wgMiBhcmUgZnVsbHkgaXNvbGF0ZWQgYXQgdGlkYWwgaGVpZ2h0cyBvZiBhcm91bmQgMCBtIChtZWFuIGxvdyBsb3cgd2F0ZXIsIE1MTFcpIG9yIGxvd2VyLCBhbmQgc3Vic3RhbnRpYWxseSBjb25uZWN0ZWQgYXQgYXJvdW5kIDAuMjUgbSBvciBoaWdoZXIuIE9uIHRoZSBkYXkgd2Ugc2FtcGxlZCwgdGhpcyBtZWFudCB3YXRlciBhY3RpdmVseSBmbG93ZWQgYmV0d2VlbiB0aGUgbG9jYXRpb25zIGF0IHRoZSBzdGFydCAoMTE6MzAgUFNUKSBhbmQgZW5kICgxNzowMCBQU1QpIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QsIGJ1dCB0aGF0IHRoZSBzaXRlcyB3ZXJlIGRpc2Nvbm5lY3RlZCBhdCBsb3cgdGlkZSBpbiB0aGUgbWlkZGxlIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QuCgojIyMjIDIuMyBTYW1wbGUgQ29sbGVjdGlvbiAmIEZpbHRyYXRpb24KCldlIGNvbGxlY3RlZCAxIEwgc3VyZmFjZSBzYW1wbGVzIGZyb20gZWFjaCBsb2NhdGlvbiBldmVyeSAzMCBtaW51dGVzIGZvciB0aGUgZHVyYXRpb24gb2YgdGltZSB0aGUgcm9ja3kgaW50ZXJ0aWRhbCB3YXMgZXhwb3NlZCBvbiAyOCBKYW51YXJ5IDIwMjIsIHVzaW5nIHNpbmdsZS11c2UgZW50ZXJhbCBmZWVkaW5nIHBvdWNoZXMgKENvdmlkaWVuLCBEdWJsaW4sIElyZWxhbmQpLiBTYW1wbGluZyBjb21tZW5jZWQgYXQgMTE6MzAgUFNUOyB0aGUgZXhhY3QgdGltZXMgb2Ygc2FtcGxlIGNvbGxlY3Rpb24sIGluIHJlbGF0aW9uIHRvIHRoZSB0aWRlLCBhcmUgc2hvd24gaW4gRmlndXJlIDMuIEZvbGxvd2luZyB0aGUgYXBwcm9hY2ggdXNlZCBieSBHb2xkIGV0IGFsLiAoMjAyMWIpLCB3ZSBhdHRhY2hlZCBhIHN0ZXJpbGUgMC4yMiAkXG11JG0gcG9yZSBzaXplIFN0ZXJpdmV4IGNhcnRyaWRnZSAoTWlsbGlwb3JlU2lnbWEsIEJ1cmxpbmd0b24sIE1BLCBVU0EpIHRvIHRoZSB0dWJpbmcgb2YgZWFjaCBmZWVkaW5nIHBvdWNoLCBhbGxvd2luZyBzYW1wbGVzIHRvIGJlIGltbWVkaWF0ZWx5IGdyYXZpdHkgZmlsdGVyZWQgaW4gdGhlIGZpZWxkLiBXaGlsZSBncmF2aXR5IGZpbHRlcmluZyAoMS0yIGhvdXJzIHBlciBzYW1wbGUpLCBzYW1wbGVzIHdlcmUgc2hhZGVkIHdpdGggYW4gYXduaW5nIHRvIHByZXZlbnQgYW55IGRlZ3JhZGF0aW9uIGJ5IHN1bmxpZ2h0IChBbmRydXN6a2lld2ljeiBldCBhbC4sIDIwMTcpLgoKYGBge3IsIEZpZ3VyZSAzfQojIyNGaWd1cmUgMyMjIwojUHJvZHVjZSB0aGUgdG9wIHBvcnRpb24gb2YgRmlndXJlIDMgZnJvbSB0aWRlIGRhdGEKCiNSZWFkIFBpbGxhciBQb2ludCBOT0FBL05PUy9DTy1PUHMgVGlkZSBDaGFydCBkYXRhIGZpbGUKVGlkZXMgPSByZWFkLnRhYmxlKCJEYXRhLzI4LUphbi0yMDIyLVRpZGVDaGFydC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiIiwgZGVjID0gIi4iLCBza2lwPTEzKQoKI0NvbnZlcnQgZGF0ZSBmb3JtYXQgaW4gdGFibGUgdXNpbmcgbHVicmlkYXRlClRpZGVzJGRhdGV0aW1lIDwtIGx1YnJpZGF0ZTo6eW1kX2htKHBhc3RlKFRpZGVzJERhdGUsIFRpZGVzJFRpbWUpLCB0eiA9ICJVUy9QYWNpZmljIikKCiNTZXQgYm91bmRzIG9mIHNhbXBsaW5nIHBlcmlvZCB0byBoaWdobGlnaHQKeG1pbiA9IFRpZGVzJGRhdGV0aW1lWzQ3XQp4bWF4ID0gVGlkZXMkZGF0ZXRpbWVbNjldCnltaW4gPSAtLjUKeW1heCA9IC41Cgpib3hfY29sb3IgPSAiIzgwODA4MCIKCiNDcmVhdGUgcGxvdCBvZiBmdWxsIHRpZGFsIGN5Y2xlIHdpdGggc2FtcGxpbmcgcGVyaW9kIGhpZ2hsaWdodGVkCnAxIDwtIGdncGxvdChkYXRhPVRpZGVzLCBhZXMoeD1kYXRldGltZSwgeSA9IFByZWQsIGdyb3VwPTEpKSArIAogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IHhtaW4sIHhtYXggPSB4bWF4LCB5bWluID0geW1pbiwgeW1heCA9IHltYXgsIGZpbGwgPSBib3hfY29sb3IpICsKICBnZW9tX2xpbmUoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKFRpZGVzJGRhdGV0aW1lWzFdLCBUaWRlcyRkYXRldGltZVs5Nl0pKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXyksIAogICAgIyBuZWNlc3NhcnkgdG8gYXZvaWQgZHJhd2luZyBwYW5lbCBvdXRsaW5lCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BX2NoYXJhY3Rlcl8pLAogICAgIyBuZWNlc3NhcnkgdG8gYXZvaWQgZHJhd2luZyBwbG90IG91dGxpbmUKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSwgbGluZXdpZHRoPTEpCiAgKSArCiAgeGxhYigiVGltZSAoUFNUKSIpICsKICB5bGFiKCJNTExXIFRpZGUgUHJlZGljdGlvbiAobSkiKSArCiAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIyIGhvdXIiLCBkYXRlX2xhYmVscyA9ICIlSDowMCIsIGV4cGFuZCA9IGMoMCwgMCksIHBvc2l0aW9uID0gInRvcCIpCgojQ3JlYXRlIHBsb3Qgb2YganVzdCBzYW1wbGluZyBwZXJpb2QKcDIgPC0gZ2dwbG90KGRhdGE9VGlkZXMsIGFlcyh4PWRhdGV0aW1lLCB5ID0gUHJlZCwgZ3JvdXA9MSkpICsgCiAgZ2VvbV9saW5lKCkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYyh4bWluLCB4bWF4KSwgeWxpbSA9IGMoeW1pbiwgeW1heCkpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKSArIAogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGJveF9jb2xvciksIAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXyksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSwgbGluZXdpZHRoPTEpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArIAogIHlsYWIoIk1MTFcgVGlkZSBQcmVkaWN0aW9uIChtKSIpICsKICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjMwIG1pbiIsIGRhdGVfbGFiZWxzID0gIiVIOiVNIiwgZXhwYW5kID0gYygwLCAwKSkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKGI9MCkpCgojU3RpdGNoIHBsb3RzIHRvZ2V0aGVyIHVzaW5nIHBhdGNod29yawpwX3BhdGNoIDwtIHAxIC8gKHAyICYgdGhlbWUocGxvdC5tYXJnaW49bWFyZ2luKDAsMCwwLDAsICJwdCIpKSkgJiB5bGFiKE5VTEwpICYgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQV9jaGFyYWN0ZXJfKSkKCiMgVXNlIHRoZSB0YWcgbGFiZWwgYXMgYSB5LWF4aXMgbGFiZWwKcF9wYXRjaCA9IHdyYXBfZWxlbWVudHMocF9wYXRjaCkgKwogIGxhYnModGFnID0gIk1MTFcgVGlkZSBQcmVkaWN0aW9uIChtKSIpICsKICB0aGVtZSgKICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSwgYW5nbGUgPSA5MCksCiAgICBwbG90LnRhZy5wb3NpdGlvbiA9ICJsZWZ0IiwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXykKICApCgoKaWYgKCFkaXIuZXhpc3RzKCJGaWd1cmVzIikpIHtkaXIuY3JlYXRlKCJGaWd1cmVzIil9CnBhdGggPSAiRmlndXJlcy9GaWd1cmUzLiIKc2F2ZV9wZGZfcG5nKHBsb3QgPSBwX3BhdGNoLCBwYXRoID0gcGF0aCwgdyA9IDE2OSwgaCA9IDkwLCB1ID0gIm1tIiwgYmcgPSAidHJhbnNwYXJlbnQiLCBkcGkgPSA2MDApCmBgYAoKPGNlbnRlcj4KCiFbKkZpcnN0IGNvbXBvbmVudCBvZiBGaWd1cmUgMyAoc2Vjb25kIHNlY3Rpb24gYWRkZWQgb25jZSBkYXRhIGhhcyBiZWVuIGxvYWRlZCpdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgpBdCB0aHJlZSB0aW1lIHBvaW50cyAoc2VlIGZ1bGwgRmlndXJlIDMsIGZpbmFsaXplZCBiZWxvdykgYXQgdGhlIGJlZ2lubmluZyBhbmQgZW5kIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QgYXMgd2VsbCBhcyBhdCBsb3cgdGlkZSAoYXQgMTQ6MDAgUFNUKSwgd2UgY29sbGVjdGVkIHRyaXBsaWNhdGUgMSBMIHNhbXBsZXMgZnJvbSBlYWNoIGxvY2F0aW9uIGFzIGJpb2xvZ2ljYWwgcmVwbGljYXRlcy4gQXQgdGhlIGJlZ2lubmluZyBhbmQgZW5kIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QsIHdlIGFsc28gZmlsdGVyZWQgMSBMIE1pbGxpUSB3YXRlciB2aWEgdGhlIHByb2NlZHVyZSBkZXNjcmliZWQgYWJvdmUgdG8gc2VydmUgYXMgbmVnYXRpdmUgZmllbGQgY29udHJvbHMuIEFkZGl0aW9uYWxseSwgdXNpbmcgYW4gT3Jpb24gTW9kZWwgMTIzMCBtZXRlciAoT3Jpb24gUmVzZWFyY2ggSW5jLiwgQmV2ZXJseSwgTUEsIFVTQSksIHdlIHJlY29yZGVkIHRlbXBlcmF0dXJlIGFuZCBzYWxpbml0eSBpbiBlYWNoIGxvY2F0aW9uIGRpcmVjdGx5IGFmdGVyIHNhbXBsZXMgd2VyZSBjb2xsZWN0ZWQuCgpPbmNlIGZpbmlzaGVkIGZpbHRlcmluZywgU3Rlcml2ZXggY2FydHJpZGdlcyB3ZXJlIGRyaWVkIGJ5IHB1c2hpbmcgYWlyIHRocm91Z2ggdGhlbSB1c2luZyBhIHN0ZXJpbGUgMyBtTCBzeXJpbmdlLCBjYXBwZWQsIHBsYWNlZCBpbiBzdGVyaWxlIFdoaXJsLVBhayBiYWdzIChXaGlybC1QYWssIE1hZGlzb24sIFdJLCBVU0EpLiBUaGVuLCBzYW1wbGVzIHdlcmUgc3RvcmVkIGluIGEgY29vbGVyIG9uIGljZSB1bnRpbCB0cmFuc3BvcnRlZCBiYWNrIHRvIHRoZSBsYWJvcmF0b3J5IGF0IHRoZSBlbmQgb2YgdGhlIHNhbXBsaW5nIHBlcmlvZC4gU2FtcGxlcyB3ZXJlIHRyYW5zZmVycmVkIHRvIGEgLTIwwrBDIGZyZWV6ZXIgZm9yIHVwIHRvIDE4IGRheXMsIGF0IHdoaWNoIHRpbWUgdGhleSB3ZXJlIHByb2Nlc3NlZCB0byBleHRyYWN0IG51Y2xlaWMgYWNpZHMgZnJvbSB0aGUgY2FwdHVyZWQgbWF0ZXJpYWxzLgoKIyMjIyAyLjQgRE5BIEV4dHJhY3Rpb24gJiBMaWJyYXJ5IFByZXBhcmF0aW9uCgpXaXRoaW4gMTggZGF5cyBvZiBjb2xsZWN0aW9uLCB3ZSBleHRyYWN0ZWQgRE5BIGZyb20gdGhlIFN0ZXJpdmV4IGNhcnRyaWRnZSB1c2luZyB0aGUgRE5lYXN5IEJsb29kIGFuZCBUaXNzdWUgS2l0IChRaWFnZW4sIEdlcm1hbnRvd24sIE1ELCBVU0EpIGFuZCB0aGUgbW9kaWZpY2F0aW9ucyBkZXNjcmliZWQgaW4gU3BlbnMgZXQgYWwuICgyMDE3KS4gSW4gc2hvcnQsIHdlIGluY3ViYXRlZCB0aGUgZmlsdGVyIGNhcnRyaWRnZSBvdmVybmlnaHQgd2l0aCBwcm90ZWluYXNlIEsgYW5kIEFUTC4gVGhlbiwgd2UgZXh0cmFjdGVkIHRoZSBsaXF1aWQgZnJvbSB0aGUgY2FydHJpZGdlIHdpdGggYSBzeXJpbmdlIGFuZCBtaXhlZCBpdCB3aXRoIGVxdWFsIHZvbHVtZXMgb2YgQUwgYnVmZmVyIGFuZCAwwrBDIGV0aGFub2wgYmVmb3JlIHByb2NlZWRpbmcgd2l0aCB0aGUgbWFudWZhY3R1cmVyJ3MgZXh0cmFjdGlvbiBwcm90b2NvbC4gT25lIG5lZ2F0aXZlIGV4dHJhY3Rpb24gY29udHJvbCAoRE5BLWdyYWRlIHdhdGVyIGluIHBsYWNlIG9mIGEgc2FtcGxlKSB3YXMgaW5jbHVkZWQgaW4gZWFjaCBvZiBmb3VyIGJhdGNoZXMgb2YgZXh0cmFjdGlvbnMuIEV4dHJhY3RlZCBzYW1wbGVzIHRvIGJlIFBDUiBhbXBsaWZpZWQgd2VyZSBzdG9yZWQgYXQgLTIwwrBDIGZvciB1cCB0byA2IG1vbnRocy4KCldlIFBDUiBhbXBsaWZpZWQgdGhlIGV4dHJhY3RlZCBETkEgaW4gdHJpcGxpY2F0ZSB3aXRoaW4gNiBtb250aHMgb2Ygc3RvcmFnZSwgdXNpbmcgdGhlIG1sQ09JaW50Ri8gamdIQ08yMTk4IHByaW1lciBzZXQgdGFyZ2V0aW5nIGEgMzEzIGJwIGZyYWdtZW50IG9mIHRoZSBtaXRvY2hvbmRyaWFsIENPSSByZWdpb24gb3B0aW1pemVkIGJ5IExlcmF5IGV0IGFsLiAoMjAxMykgKEZvcndhcmQ6IEdHV0FDV0dHV1RHQUFDV0dUV1RBWUNDWUNDOyBSZXZlcnNlOiBUQUlBQ1lUQ0lHR1JUR0lDQ1JBQVJBQVlDQSkgd2l0aCBOZXh0ZXJhIG1vZGlmaWNhdGlvbnMuIEZvbGxvd2luZyBDdXJkIGV0IGFsLiAoMjAxOSksIHdlIHVzZWQgYSAyNSAkXG11JGwgUENSIHJlYWN0aW9uIG1peHR1cmUgY29uc2lzdGluZyBvZiAxMi41ICRcbXUkbCBvZiBRaWFnZW4gTXVsdGlwbGV4IE1peCAoUWlhZ2VuLCBHZXJtYW50b3duLCBNRCwgVVNBKSwgMi41ICRcbXUkbCBlYWNoIG9mIHRoZSBmb3J3YXJkIGFuZCByZXZlcnNlIHByaW1lcnMgYXQgMiAkXG11JE0gKEludGVncmF0ZWQgRE5BIFRlY2hub2xvZ2llcywgSW5jLiwgQ29yYWx2aWxsZSwgSUEsIFVTQSksIDYuNSAkXG11JGwgb2YgUENSLWdyYWRlIHdhdGVyLCBhbmQgMSAkXG11JGwgb2YgdW5kaWx1dGVkIEROQSB0ZW1wbGF0ZS4gVGhlIFBDUiB0aGVybW9jeWNsaW5nIHRvdWNoZG93biBwcm9maWxlIGJlZ2FuIHdpdGggYW4gaW5pdGlhbCBkZW5hdHVyYXRpb24gYXQgOTXCsCBmb3IgMTUgbWludXRlcyB0byBhY3RpdmF0ZSB0aGUgRE5BIHBvbHltZXJhc2UsIGZvbGxvd2VkIGJ5IDEzIGN5Y2xlcyBvZiBkZW5hdHVyYXRpb24gKDk0wrAgZm9yIDMwIHNlY29uZHMpLCBhbm5lYWxpbmcgKHN0YXJ0aW5nIGF0IDY5LjXCsCBmb3IgMzAgc2Vjb25kcywgd2l0aCB0aGUgdGVtcGVyYXR1cmUgZGVjcmVhc2VkIGJ5IDEuNcKwIGVhY2ggY3ljbGUpLCBhbmQgZXh0ZW5zaW9uICg3MsKwIGZvciAxIG1pbnV0ZSkuIFRoZW4sIGFuIGFkZGl0aW9uYWwgMzUgY3ljbGVzIHdlcmUgcnVuIHdpdGggdGhlIHNhbWUgZGVuYXR1cmF0aW9uIGFuZCBleHRlbnNpb24gc3RlcHMgYXMgYWJvdmUgd2l0aCBhbiBhbm5lYWxpbmcgdGVtcGVyYXR1cmUgb2YgNTDCsCwgZm9sbG93ZWQgYnkgYSBmaW5hbCBleHRlbnNpb24gYXQgNzLCsCBmb3IgMTAgbWludXRlcy4gUENSIHJlYWN0aW9ucyB3ZXJlIHByZXBhcmVkIGluIGEgZGVzaWduYXRlZCBETkEtZnJlZSBob29kIHVudGlsIHRoZSB0ZW1wbGF0ZSB3YXMgYWRkZWQuCgpQQ1IgYW1wbGlmaWNhdGlvbiB3YXMgY29uZHVjdGVkIGluIHR3byBiYXRjaGVzOyBpbiBlYWNoIGJhdGNoLCB3ZSBpbmNsdWRlZCBvbmUgbm8tdGVtcGxhdGUgbmVnYXRpdmUgUENSIGNvbnRyb2wgKEROQS1ncmFkZSB3YXRlciB1c2VkIGFzIHRlbXBsYXRlKS4gQWRkaXRpb25hbGx5LCB3ZSBleHRyYWN0ZWQgRE5BIGZyb20gdGlzc3VlIGZyb20gZml2ZSBvcmdhbmlzbXMgYWNyb3NzIGEgcmFuZ2Ugb2YgcGh5bGEgd2UgZXhwZWN0ZWQgdG8gYW1wbGlmeSB3aXRoIHRoZSBtbENPSWludEYvIGpnSENPMjE5OCBwcmltZXJzLCBidXQgbm90IGV4cGVjdGVkIHRvIGJlIHByZXNlbnQgYXQgUGlsbGFyIFBvaW50IGluIHBhcnRpY3VsYXIgKCpNeXRpbHVzIGVkdWxpcyosICpNaXp1aG9wZWN0ZW4geWVzc29lbnNpcyosICpYaXBoaWFzIGdsYWRpdXMqLCAqTWVyY2VuYXJpYSBtZXJjZW5hcmlhKiwgKkx1dGphbnVzIGNhbXBlY2hhbnVzKikgdXNpbmcgdGhlIHN0YW5kYXJkIHRpc3N1ZSBleHRyYWN0aW9uIHByb3RvY29sIGRldGFpbGVkIGluIHRoZSBETmVhc3kgQmxvb2QgYW5kIFRpc3N1ZSBLaXQgKFFpYWdlbiwgR2VybWFudG93biwgTUQsIFVTQSkuIFRoZXNlIHRpc3N1ZXMgd2VyZSBvYnRhaW5lZCBmcm9tIGEgbG9jYWwgZ3JvY2VyeSBzdG9yZSBhbmQgaXQgd2FzIGFzc3VtZWQgdGhhdCB0aGV5IHdlcmUgbGFiZWxlZCBjb3JyZWN0bHksIGFsdGhvdWdoIHByZXZpb3VzIHdvcmsgaGFzIGluZGljYXRlZCBtaXNsYWJlbGluZyBpbiBzZWFmb29kIHN0b3JlcyBjYW4gb2NjdXIgKGUuZy4gV2lsbGV0dGUgZXQgYWwuLCAyMDE3KS4gRXh0cmFjdHMgZnJvbSB0aGUgNSB0aXNzdWUgc2FtcGxlcyB3ZXJlIGNvbWJpbmVkIGluIGVxdWltb2xhciBhbW91bnRzIHRvIGZvcm0gYSBtb2NrIGNvbW11bml0eSB1c2VkIGFzIGEgcG9zaXRpdmUgUENSIGNvbnRyb2wgaW4gZWFjaCBiYXRjaC4gVHJpcGxpY2F0ZSBQQ1IgYW1wbGljb25zIGZyb20gYm90aCBzYW1wbGVzIGFuZCBjb250cm9scyB3ZXJlIG5vdCBzdWJzZXF1ZW50bHkgcG9vbGVkLCBidXQgd2VyZSBjYXJyaWVkIHRocm91Z2ggdGhlIHJlbWFpbmluZyBsaWJyYXJ5IHByZXBhcmF0aW9uIGFuZCBzZXF1ZW5jaW5nIHN0ZXBzIGFzIHRlY2huaWNhbCByZXBsaWNhdGVzLiBXZSBlbGVjdHJvcGhvcmVzZWQgYW5kIHZpc3VhbGl6ZWQgYSBzdWJzZXQgb2YgUENSIHByb2R1Y3RzIG9uIGEgMS41JSBhZ2Fyb3NlIGdlbCBzdGFpbmVkIHdpdGggR2VsUmVkwq4gKEJpb3RpdW0sIEZyZW1vbnQsIENBLCBVU0EpIHRvIGVuc3VyZSBzdWNjZXNzZnVsIGFtcGxpZmljYXRpb24gYW5kIGNvcnJlY3QgcHJvZHVjdCBzaXplcyBhcyB3ZWxsIGFzIGxhY2sgb2YgY29udGFtaW5hdGlvbi4KClBvc3QtUENSIGxpYnJhcnkgcHJlcGFyYXRpb24gYW5kIHNlcXVlbmNpbmcgd2FzIGNvbmR1Y3RlZCBhdCB0aGUgR2VvcmdpYSBHZW5vbWljcyBhbmQgQmlvaW5mb3JtYXRpY3MgQ29yZSAoR0dCQywgVUcgQXRoZW5zLCBHQSwgUlJJRDpTQ1JfMDEwOTk0KS4gSW4gc2hvcnQsIHByb3ZpZGVkIFBDUiBhbXBsaWNvbnMgd2VyZSBjbGVhbmVkIHVzaW5nIEFNUHVyZSBYUCBtYWduZXRpYyBiZWFkcyAoQmVja21hbiBDb3VsdGVyLCBJbmRpYW5hcG9saXMsIElOLCBVU0EpLCBiYXJjb2RlZCB3aXRoIE5leHRlcmEgYWRhcHRlcnMgKElsbHVtaW5hLCBTYW4gRGllZ28sIENBLCBVU0EpIGR1cmluZyBhIHNlY29uZCBQQ1IgKDMgbWluIGF0IDk1wrBDOyAxNSBjeWNsZXMgb2YgMzAgc2VjIGF0IDk1wrBDLCAzMCBzZWMgYXQgNjfCsEMsIGFuZCAzMCBzZWMgYXQgNzLCsEM7IGFuZCA0IG1pbiBhdCA3MsKwQyksIGNsZWFuZWQgYWdhaW4gdXNpbmcgQU1QdXJlWFAgbWFnbmV0aWMgYmVhZHMsIGFuZCBwb29sZWQgaW4gZXF1aW1vbGFyIHJhdGlvLiBUaGUgcmVzdWx0aW5nIGxpYnJhcnkgd2FzIHNlcXVlbmNlZCBvbiBhIE1pU2VxIFBFIDJ4MjUwYnAgKDUwMCBjeWNsZXMpIHVzaW5nIFJlYWdlbnQgS2l0IFYyIHdpdGggMjUlIFBoaVggc3Bpa2UtaW4gKElsbHVtaW5hLCBTYW4gRGllZ28sIENBLCBVU0EpLiBHaXZlbiBvdXIgdGVjaG5pY2FsIHJlcGxpY2F0aW9uIG9mIHNhbXBsZXMgYW5kIGNvbnRyb2xzLCBvdXIgZmluYWwgbGlicmFyeSBpbmNsdWRlZCA2IG5lZ2F0aXZlIGZpZWxkIGNvbnRyb2xzICgxIGF0IGJlZ2lubmluZyBhbmQgZW5kIG9mIGZpZWxkIHNhbXBsaW5nLCBhbXBsaWZpZWQgaW4gdHJpcGxpY2F0ZSksIDEyIG5lZ2F0aXZlIGV4dHJhY3Rpb24gY29udHJvbHMgKDEgaW4gZWFjaCBvZiA0IGV4dHJhY3Rpb24gc2V0cywgYW1wbGlmaWVkIGluIHRyaXBsaWNhdGUpLCAyIHBvc2l0aXZlIFBDUiBjb250cm9scyAoMSBpbiBlYWNoIG9mIDIgYW1wbGlmaWNhdGlvbiBiYXRjaGVzKSwgMiBuby10ZW1wbGF0ZSBuZWdhdGl2ZSBQQ1IgY29udHJvbHMgKDEgaW4gZWFjaCBvZiAyIGFtcGxpZmljYXRpb24gYmF0Y2hlcyksIGFuZCAxNTkgc2FtcGxlcyAoNTMgZmllbGQgc2FtcGxlcywgYW1wbGlmaWVkIGluIHRyaXBsaWNhdGUpLgoKIyMjIyAyLjUgQmlvaW5mb3JtYXRpY3MKCldlIHByb2Nlc3NlZCBzZXF1ZW5jaW5nIGRhdGEgdXNpbmcgdGhlIEFuYWNhcGEgVG9vbGtpdCwgd2hpY2ggY29udGFpbnMgdHdvIGNvcmUgbW9kdWxlczogb25lIGZvciBxdWFsaXR5IGNvbnRyb2wgYW5kIEFTViBwYXJzaW5nLCBhbmQgb25lIGZvciBjbGFzc2lmeWluZyB0YXhvbm9teSAoQ3VyZCBldCBhbC4sIDIwMTkpLiBCcmllZmx5LCB3ZSByYW4gdGhlIGZpcnN0IG1vZHVsZSB1c2luZyBkZWZhdWx0IHBhcmFtZXRlcnMsIHdoaWNoIHVzZXMgY3V0YWRhcHQgKHZlcnNpb24gMS4xNikgKE1hcnRpbiwgMjAxMSkgZm9yIGFkYXB0ZXIgYW5kIHByaW1lciB0cmltbWluZywgRmFzdFgtVG9vbGtpdCAodmVyc2lvbjogMC4wLjEzKSAoY2l0YXRpb24pIGZvciBxdWFsaXR5IHRyaW1taW5nLCBhbmQgZGFkYTIgKHZlcnNpb24gMS42KSAoQ2FsbGFoYW4gZXQgYWwuLCAyMDE2KSBmb3IgYXNzaWduaW5nIEFTVnMuIEZvciB0aGUgc2Vjb25kIG1vZHVsZSwgd2UgdXRpbGl6ZWQgdGhlIE1JRE9SSTIgcmVmZXJlbmNlIGRhdGFiYXNlLCBhIHF1YWxpdHkgY29udHJvbGxlZCBhbmQgdXBkYXRlZCBkYXRhYmFzZSBidWlsdCBmcm9tIEdlbkJhbmsgcmVsZWFzZSAyNTMgKDIwIERlY2VtYmVyIDIwMjIpIHRoYXQgaGFzIGJlZW4gdGVjaG5pY2FsbHkgdmFsaWRhdGVkIChMZXJheSBldCBhbC4sIDIwMjIpLiBGb2xsb3dpbmcgR29sZCBldCBhbC4gKDIwMjIpLCB3ZSBhZGp1c3RlZCB0aGUgaWRlbnRpdHkgYW5kIHF1ZXJ5IGNvdmVyYWdlIHRvIDk1JSAoZGVmYXVsdDogODAlKSB0byBhY2NvdW50IGZvciB0aGUgcmVsYXRpdmUgaW5jb21wbGV0ZW5lc3Mgb2YgdGhlIGJyb2FkIENPSSByZWZlcmVuY2UgZGF0YWJhc2UgY29tcGFyZWQgdG8gbW9yZSB0YXhvbm9taWNhbGx5LXNwZWNpZmljIGRhdGFiYXNlcyAoQ3VyZCBldCBhbC4sIDIwMTkpLiBUaGUgc2Vjb25kIG1vZHVsZSByZWxpZXMgb24gQm93dGllIDIgKHZlcnNpb24gMi4zLjUpIChMYW5nbWVhZCBhbmQgU2FsemJlcmcsIDIwMTIpIGFuZCBhIG1vZGlmaWVkIGluc3RhbmNlIG9mIEJMQ0EgKEdhbyBldCBhbC4sIDIwMTcpIGFzIGRlcGVuZGVuY2llcy4gRm9sbG93aW5nIEdvbGQgZXQgYWwuICgyMDIxYSkgd2Ugb25seSBrZXB0IHRheG9ub21pYyBhc3NpZ25tZW50cyB0aGF0IGhhZCBhIGJvb3RzdHJhcCBjb25maWRlbmNlIGN1dG9mZiBzY29yZSBvZiA2MCBvciBoaWdoZXIgaW4gQkxDQSwgdG8gYXZvaWQgc3B1cmlvdXMgYXNzaWdubWVudHMgZnJvbSB0aGUgaW5jb21wbGV0ZSByZWZlcmVuY2UgZGF0YWJhc2UuIFdlIG1vZGlmaWVkIHRoZSBBbmFjYXBhIENvbnRhaW5lciAoT2dkZW4sIDIwMTgpLCBhIFNpbmd1bGFyaXR5IGNvbnRhaW5lciB3aXRoIGFsbCB0aGUgbmVlZGVkIGRlcGVuZGVuY2llcyBmb3IgZXhlY3V0aW5nIHRoZSBBbmFjYXBhIFRvb2xraXQsIHRvIGVuYWJsZSB0aGUgcGlwZWxpbmUgdG8gYmUgcnVuIGluIGEgaGlnaC1wZXJmb3JtYW5jZSBjb21wdXRpbmcgZW52aXJvbm1lbnQgcmVxdWlyaW5nIHR3by1zdGVwIGF1dGhlbnRpY2F0aW9uOyB0aGUgdXBkYXRlZCBjb250YWluZXIsIHNjcmlwdHMsIGFuZCByZWZlcmVuY2UgZGF0YWJhc2Ugd2l0aCB0aGUgcmVxdWlyZWQgQm93dGllIDIgaW5kZXggbGlicmFyeSBuZWVkZWQgdG8gcmVwcm9kdWNlIG91ciBiaW9pbmZvcm1hdGljcyBwcm9jZXNzIGNhbiBiZSBmb3VuZCBvbiBEcnlhZCAobGluay9jaXRhdGlvbikuCgpSYXcgQVNWcywgdGF4b25vbXkgYXNzaWdubWVudHMsIGFuZCBtZXRhZGF0YSB3ZXJlIGNvbnZlcnRlZCBpbnRvIGludGVyY2hhbmdlYWJsZSBgYW1wdmlzMmAgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oImFtcHZpczIiKWAgYHBhY2thZ2VWZXJzaW9uKCJhbXB2aXMyIilgKSAoQW5kZXJzZW4gZXQgYWwuLCAyMDE4KSBhbmQgYHBoeWxvc2VxYCAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigicGh5bG9zZXEiKWAgYHBhY2thZ2VWZXJzaW9uKCJwaHlsb3NlcSIpYCkgKE1jTXVyZGllIGFuZCBIb2xtZXMsIDIwMTMpIG9iamVjdHMgaW4gYHIgUi5WZXJzaW9uKCkkdmVyc2lvbi5zdHJpbmdgIGBSLlZlcnNpb24oKSR2ZXJzaW9uLnN0cmluZ2AgdG8gZmFjaWxpdGF0ZSBkZWNvbnRhbWluYXRpb24gYW5kIGZ1cnRoZXIgYW5hbHlzZXMuIFNpbmdsZXRvbnMgd2VyZSByZW1vdmVkIHVzaW5nIGBhbXB2aXMyYCwgYW5kIHNhbXBsZXMgd2VyZSBmdXJ0aGVyIGRlY29udGFtaW5hdGVkIHVzaW5nIGBwaHlsb3NlcWAgYnkgcmVtb3ZpbmcgYWxsIEFTVnMgdGhhdCBhcHBlYXJlZCBpbiBhbnkgbmVnYXRpdmUgZmllbGQgY29udHJvbCwgbmVnYXRpdmUgZXh0cmFjdGlvbiBjb250cm9sLCBvciBuby10ZW1wbGF0ZSBuZWdhdGl2ZSBQQ1IgY29udHJvbCwgYSBjaG9pY2UgbWFkZSBkdWUgdG8gdGhlIHZlcnkgbG93IG51bWJlciBvZiBvdmVybGFwcGluZyBBU1ZzIGJldHdlZW4gc2FtcGxlcyBhbmQgbmVnYXRpdmUgY29udHJvbHMgKFRhYmxlIFMxKS4gU2FtcGxlcyB3ZXJlIHJhcmlmaWVkIHRvIHRoZSBtaW5pbXVtIG51bWJlciBvZiByZWFkcyBvZiBhbnkgc2FtcGxlIHVzaW5nIGBhbXB2aXMyYC4gU3Vic2VxdWVudCBhbmFseXNlcyB3ZXJlIHJvYnVzdCB0byBhbGwgdGhyZWUgZGVjb250YW1pbmF0aW9uIHN0ZXBzLgoKYGBge3IgSW1wb3J0aW5nIEFuYWNhcGEsIHdhcm5pbmcgPSBGQUxTRX0KIyMjSW1wb3J0aW5nIEFuYWNhcGEjIyMKI1JlYWQgaW4gQW5hY2FwYSBQaXBlbGluZSBPdXRwdXQgYW5kIHByb2Nlc3MgaW50byBhbXB2aXMyIG9iamVjdHMgZm9yIHVzZSBpbiBhbmFseXNlcwoKI1JlYWQgaW4gQW5hY2FwYSBPdXRwdXQKI0NoYW5nZSBwX2NvbmZpZGVuY2UgdG8gc3dpdGNoIHRvIGEgZGlmZmVyZW50IHBlcmNlbnQgY29uZmlkZW5jZSBvdXRwdXQKIyMjCnBfY29uZmlkZW5jZSA9IDYwCiMjIwpjdXJyZW50X3N1YmZvbGRlciA9ICJEYXRhL0FuYWNhcGEgUGlwZWxpbmUgT3V0cHV0L1RpZGUgUG9vbCA1MTg0IC0gMzEgSmFudWFyeSAyMDIzIgoKZmlsZXBhdGggPSBwYXN0ZTAoY3VycmVudF9zdWJmb2xkZXIsIAogICAgICAgICAgICAgICAgICAiL0NPMS9DTzFfdGF4b25vbXlfdGFibGVzL1N1bW1hcnlfYnlfcGVyY2VudF9jb25maWRlbmNlLyIsIAogICAgICAgICAgICAgICAgICBwX2NvbmZpZGVuY2UsIAogICAgICAgICAgICAgICAgICAiL0NPMV9BU1ZfcmF3X3RheG9ub215XyIsIAogICAgICAgICAgICAgICAgICBwX2NvbmZpZGVuY2UsIAogICAgICAgICAgICAgICAgICAiLnR4dCIpCgpBbmFjYXBhT3V0cHV0ID0gcmVhZC50YWJsZShmaWxlcGF0aCwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0IiwgZGVjID0gIi4iKQoKI0Zvcm1hdCBBU1YgVGFibGUgKGV4dHJhY3QganVzdCB0aGUgbmVlZGVkIGluZm9ybWF0aW9uKQplbmRjb2wgPSBuY29sKEFuYWNhcGFPdXRwdXQpIC0gMQphc3ZtYXQgPSBBbmFjYXBhT3V0cHV0WywyOmVuZGNvbF0Kcm93bmFtZXMoYXN2bWF0KSA8LSBBbmFjYXBhT3V0cHV0WywxXQoKI0Zvcm1hdCBUYXhvbm9teSBUYWJsZSAoZXh0cmFjdCBqdXN0IHRoZSBuZWVkZWQgaW5mb3JtYXRpb24gYW5kIHJlbmFtZSBjb2x1bW5zKQplbmRjb2wgPSBuY29sKEFuYWNhcGFPdXRwdXQpCnRheG1hdCA9IEFuYWNhcGFPdXRwdXRbLGVuZGNvbF0KdGF4bWF0ID0gc3RyX3NwbGl0X2ZpeGVkKHRheG1hdCwgIjsiLDcpCmNvbG5hbWVzKHRheG1hdCkgPC0gYygiS2luZ2RvbSIsICJQaHlsdW0iLCAiQ2xhc3MiLCAiT3JkZXIiLCAiRmFtaWx5IiwgIkdlbnVzIiwgIlNwZWNpZXMiKQpyb3duYW1lcyh0YXhtYXQpIDwtIHJvd25hbWVzKGFzdm1hdCkKCiNSZWFkIE1ldGFkYXRhIChzYXZlZCBpbiBtdWx0aXBsZSBkaWZmZXJlbnQgZmlsZXMpCgpjdXJyZW50X3N1YmZvbGRlciA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwgIi9NZXRhZGF0YS1BZGRlZC9QaWxsYXJQb2ludF9TYW1wbGVJbmZvXyIpIAoKZmlsZXBhdGggPSBwYXN0ZTAoY3VycmVudF9zdWJmb2xkZXIsICJFbnZpcm9EYXRhLnR4dCIpCkVudmlyb0RhdGEgPSByZWFkLnRhYmxlKGZpbGVwYXRoLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiLCBkZWMgPSAiLiIsIHN0cmlwLndoaXRlID0gVFJVRSkKCmZpbGVwYXRoID0gcGFzdGUwKGN1cnJlbnRfc3ViZm9sZGVyLCAiRmllbGRTYW1wbGluZy50eHQiKQpGaWVsZFNhbXBsaW5nID0gcmVhZC50YWJsZShmaWxlcGF0aCwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0IiwgZGVjID0gIi4iLCBzdHJpcC53aGl0ZSA9IFRSVUUpCkZpZWxkU2FtcGxpbmcgPSBGaWVsZFNhbXBsaW5nWywxOjRdCgpmaWxlcGF0aCA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwgIlNlcXVlbmNpbmcudHh0IikKU2VxdWVuY2luZyA9IHJlYWQudGFibGUoZmlsZXBhdGgsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIGRlYyA9ICIuIiwgc3RyaXAud2hpdGUgPSBUUlVFKQoKZmlsZXBhdGggPSBwYXN0ZTAoY3VycmVudF9zdWJmb2xkZXIsICJMb2NhdGlvbi50eHQiKQpMb2NhdGlvbiA9IHJlYWQudGFibGUoZmlsZXBhdGgsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIGRlYyA9ICIuIiwgc3RyaXAud2hpdGUgPSBUUlVFKQoKI0Zvcm1hdCBNZXRhZGF0YQpzYW1wbGVkYXRhID0gbWVyZ2UoRmllbGRTYW1wbGluZywgRW52aXJvRGF0YSwgYWxsPVQpCnNhbXBsZWRhdGEgPSBzYW1wbGVkYXRhICU+JSBkcm9wX25hKERlcmVwbGljYXRlZF9TYW1wbGVfTmFtZSkgCiNyZW1vdmluZyBvbmUgc2FtcGxlIHRoYXQgaGFzIEVudmlyb0RhdGEgcmVhZGluZyBidXQgdGhlIGZpZWxkIHNhbXBsZSB3YXMgbm90IHByb2Nlc3NlZAoKc2FtcGxlZGF0YSA9IG1lcmdlKFNlcXVlbmNpbmcsc2FtcGxlZGF0YSwgYWxsPVQpCnJvd25hbWVzKHNhbXBsZWRhdGEpIDwtIHNhbXBsZWRhdGFbLCJYIl0KCnNhbXBsZWRhdGEkRGVyZXBsaWNhdGVkX1NhbXBsZV9OYW1lID0gYXMuZmFjdG9yKHNhbXBsZWRhdGEkRGVyZXBsaWNhdGVkX1NhbXBsZV9OYW1lKQpzYW1wbGVkYXRhJFR5cGUgPSBhcy5mYWN0b3Ioc2FtcGxlZGF0YSRUeXBlKQpzYW1wbGVkYXRhJFBDUiA9IGFzLmZhY3RvcihzYW1wbGVkYXRhJFBDUikKc2FtcGxlZGF0YSRUaW1lID0gYXMuZmFjdG9yKHNhbXBsZWRhdGEkVGltZSkKc2FtcGxlZGF0YSRMb2NhdGlvbiA9IGFzLmZhY3RvcihzYW1wbGVkYXRhJExvY2F0aW9uKQpzYW1wbGVkYXRhJEV4dHJhY3Rpb24gPSBhcy5mYWN0b3Ioc2FtcGxlZGF0YSRFeHRyYWN0aW9uKQpzYW1wbGVkYXRhJFNpdGVCeVRpbWUgPSBhcy5mYWN0b3IocGFzdGUoc2FtcGxlZGF0YSRMb2NhdGlvbiwgc2FtcGxlZGF0YSRUaW1lKSkKCiNNYWtlIGFtcHZpczIgb2JqZWN0cyB3aXRob3V0IGFueSBwcmUtcHJvY2Vzc2luZwphc3ZtYXRfYW1wID0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oYXN2bWF0LCAiQVNWIikKc2FtcGxlZGF0YV9hbXAgPSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihzYW1wbGVkYXRhLCAiU2FtcGxlIikKdGF4bWF0X2FtcCA9IHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUodGF4bWF0KSwgIkFTViIpCmFtcCA9IGFtcF9sb2FkKGFzdm1hdF9hbXAsIG1ldGFkYXRhID0gc2FtcGxlZGF0YV9hbXAsIHRheG9ub215ID0gdGF4bWF0X2FtcCkKCmFtcF9ub2NvbnRyb2xzID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGFtcCwgVHlwZSAlaW4lIGMoInNhbXBsZSIpKQphbXBfY29udHJvbHMgPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wLCBUeXBlICVpbiUgYygiY29udHJvbCIpKQoKI01ha2UgYW1wdmlzMiBvYmplY3RzIHdpdGggc2luZ2xldG9ucyByZW1vdmVkCmFtcF9OUyA9IGFtcF9sb2FkKGFzdm1hdF9hbXAsIG1ldGFkYXRhID0gc2FtcGxlZGF0YV9hbXAsIHRheG9ub215ID0gdGF4bWF0X2FtcCwgcHJ1bmVTaW5nbGV0b25zID0gVFJVRSkKCmFtcF9ub2NvbnRyb2xzX05TID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGFtcF9OUywgVHlwZSAlaW4lIGMoInNhbXBsZSIpKQphbXBfY29udHJvbHNfTlMgPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wX05TLCBUeXBlICVpbiUgYygiY29udHJvbCIpKQoKI01ha2UgYW1wdmlzMiBvYmplY3RzIHdpdGggYSBmdWxsIGRlY29udGFtaW5hdGlvbiBwcm9jZWR1cmUgCgojRnVuY3Rpb24gdGhhdCByZW1vdmVzIGFueSBBU1YgdGhhdCBhcHBlYXJzIGluIGFueSBjb250cm9sIGZyb20gYWxsIHNhbXBsZXMKZnVsbF9kZWNvbnRhbWluYXRpb24gPC1mdW5jdGlvbihhbXApIHsKICAKICBwaHlzZXEgPSBhbXBfdG9fcGh5bG9zZXEoYW1wLCBOVUxMLCBOVUxMLCBOVUxMKQogIAogIHBoeXNlcV9jb250cm9scyA8LSBwaHlzZXEgJT4lCiAgICBzdWJzZXRfc2FtcGxlcyhUeXBlID09ICJjb250cm9sIikgJT4lCiAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+MCwgLikKICAKICBiYWRBU1YgPSB0YXhhX25hbWVzKHBoeXNlcV9jb250cm9scykKICBhbGxBU1YgPSB0YXhhX25hbWVzKHBoeXNlcSkKICBhbGxBU1YgPC0gYWxsQVNWWyEoYWxsQVNWICVpbiUgYmFkQVNWKV0KICBwaHlzZXFfRkQgPSBwcnVuZV90YXhhKGFsbEFTViwgcGh5c2VxKQogIAogIGF2Ml9vdHV0YWJsZSA8LSBkYXRhLmZyYW1lKG90dV90YWJsZShwaHlzZXFfRkQpQC5EYXRhKQogIGF2Ml90YXh0YWJsZSA8LSBkYXRhLmZyYW1lKHRheF90YWJsZShwaHlzZXFfRkQpQC5EYXRhKQogIGF2Ml9tZXRhZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKHBoeXNlcV9GRCkpCiAgCiAgYW1wX3JldHVybiA8LSBhbXBfbG9hZChhdjJfb3R1dGFibGUsIG1ldGFkYXRhID0gYXYyX21ldGFkYXRhLCB0YXhvbm9teSA9IGF2Ml90YXh0YWJsZSkKICBhbXBfcmV0dXJuPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wX3JldHVybiwgVHlwZSAlaW4lIGMoInNhbXBsZSIpKQogIAogIHJldHVybihhbXBfcmV0dXJuKQp9CgphbXBfbm9jb250cm9sc19GRCA9IGZ1bGxfZGVjb250YW1pbmF0aW9uKGFtcCkKYW1wX25vY29udHJvbHNfTlNfRkQgPSBmdWxsX2RlY29udGFtaW5hdGlvbihhbXBfTlMpCgojTWFrZSBhbXB2aXMyIG9iamVjdHMgYnkgcmFyZWZ5aW5nIHRvIHRoZSBtaW5pbXVtIG51bWJlciBvZiByZWFkcyBvZiBhbnkgc2FtcGxlCgojRnVuY3Rpb24gdGhhdCB3cmFwcyBhcm91bmQgYW4gYW1wdmlzMiBmdW5jdGlvbiB0byByYXJlZnkgc2FtcGxlcyB0byB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVhZHMgb2YgYW55IHNhbXBsZQpyYXJlZmFjdGlvbiA8LSBmdW5jdGlvbihhbXApIHsKICBzZXQuc2VlZCgwKQogIHJlYWRzIDwtIGNvbFN1bXMoYW1wJGFidW5kKQogIG1pbnJlYWRzIDwtIG1pbihyZWFkcykKICBhbXBfUiA9IGFtcF9zdWJzZXRfc2FtcGxlcyhhbXAsIHJhcmVmeSA9IG1pbnJlYWRzKQogIHJldHVybihhbXBfUikKfQogIAphbXBfbm9jb250cm9sc19SID0gcmFyZWZhY3Rpb24oYW1wX25vY29udHJvbHMpCmFtcF9ub2NvbnRyb2xzX05TX1IgPSByYXJlZmFjdGlvbihhbXBfbm9jb250cm9sc19OUykKYW1wX25vY29udHJvbHNfRkRfUiA9IHJhcmVmYWN0aW9uKGFtcF9ub2NvbnRyb2xzX0ZEKQphbXBfbm9jb250cm9sc19OU19GRF9SID0gcmFyZWZhY3Rpb24oYW1wX25vY29udHJvbHNfTlNfRkQpCmBgYAoKYGBge3IgTWFraW5nIEdCSUYgRGF0YSBGcmFtZXMsIHdhcm5pbmcgPSBGQUxTRX0KIyMjTWFraW5nIEdCSUYgRGF0YSBGcmFtZXMjIyMKIyNDcmVhdGUgZGF0YSBmcmFtZXMgZm9yIHN1Ym1pc3Npb24gdG8gR0JJRgojRXhwb3J0IHZlcnNpb24gb2YgZGF0YSB3aXRoIGRlY29udGFtaW5hdGlvbiBhbmQgY29udHJvbHMgcmVtb3ZlZCBidXQgbm8gYWRkaXRpb25hbCBwcm9jZXNzaW5nCgpHQklGX2V4cG9ydCA9IGFtcF9ub2NvbnRyb2xzX0ZECgpHQklGX2V4cG9ydCRtZXRhZGF0YSA9IG1lcmdlKEdCSUZfZXhwb3J0JG1ldGFkYXRhLCBMb2NhdGlvbiwgYWxsPVQpCgpUaW1lWm9uZSA9ICJVVEPiiJIwODowMCIKRGF0ZSA9ICIyOCBKYW51YXJ5IDIwMjIiCkdCSUZfZXhwb3J0JG1ldGFkYXRhID0gY2JpbmQoR0JJRl9leHBvcnQkbWV0YWRhdGEsIFRpbWVab25lKQpHQklGX2V4cG9ydCRtZXRhZGF0YSA9IGNiaW5kKEdCSUZfZXhwb3J0JG1ldGFkYXRhLCBEYXRlKQoKbmFtZXMoR0JJRl9leHBvcnQkbWV0YWRhdGEpW25hbWVzKEdCSUZfZXhwb3J0JG1ldGFkYXRhKSA9PSAnU2FtcGxlJ10gPC0gJ1NlcXVlbmNpbmdfU2FtcGxlX05hbWUnCgpjb2xfb3JkZXIgPSBjKCJTZXF1ZW5jaW5nX1NhbXBsZV9OYW1lIiwgIlNhbXBsZV9OYW1lIiwgIkxvY2F0aW9uIiwgIkxhdGl0dWRlIiwgIkxvbmdpdHVkZSIsICJDUlMiLCAiRGF0ZSIsICJUaW1lIiwgIlRpbWVab25lIiwgIlQiLCAiUyIpCkdCSUZfZXhwb3J0JG1ldGFkYXRhID0gR0JJRl9leHBvcnQkbWV0YWRhdGFbLGNvbF9vcmRlcl0KCiNBZGQgc2VxdWVuY2VzIHRvIGZpbGUKCmN1cnJlbnRfc3ViZm9sZGVyID0gIkRhdGEvQW5hY2FwYSBQaXBlbGluZSBPdXRwdXQvVGlkZSBQb29sIDUxODQgLSAzMSBKYW51YXJ5IDIwMjMiCmZpbGVwYXRoID0gcGFzdGUwKGN1cnJlbnRfc3ViZm9sZGVyLCAKICAgICAgICAgICAgICAgICAgIi9DTzEvQ08xX3RheG9ub215X3RhYmxlcy9DTzFfQVNWX3RheG9ub215X2RldGFpbGVkLnR4dCIpCgpBbmFjYXBhRGV0YWlsZWQgPSByZWFkLnRhYmxlKGZpbGVwYXRoLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiLCBkZWMgPSAiLiIpCnNlcXVlbmNlcyA9IGFzLmRhdGEuZnJhbWUoQW5hY2FwYURldGFpbGVkWyxjKCJzZXF1ZW5jZSIsICJzZXF1ZW5jZXNGIiwgInNlcXVlbmNlc1IiKV0pCnJvd25hbWVzKHNlcXVlbmNlcykgPSBBbmFjYXBhRGV0YWlsZWQkQ08xX3NlcV9udW1iZXIKCkdCSUZfZXhwb3J0JHRheCA9IG1lcmdlKHNlcXVlbmNlcywgR0JJRl9leHBvcnQkdGF4LCBieSA9ICJyb3cubmFtZXMiLCBhbGwueCA9IEZBTFNFLCBhbGwueSA9IFRSVUUsIHNvcnQgPSBGQUxTRSkKcm93bmFtZXMoR0JJRl9leHBvcnQkdGF4KSA9IEdCSUZfZXhwb3J0JHRheCRSb3cubmFtZXMKCmNvbF9vcmRlciA9IGMoInNlcXVlbmNlIiwgInNlcXVlbmNlc0YiLCAic2VxdWVuY2VzUiIsICJLaW5nZG9tIiwgIlBoeWx1bSIsICJDbGFzcyIsICJPcmRlciIsICJGYW1pbHkiLCAiR2VudXMiLCAiU3BlY2llcyIpCkdCSUZfZXhwb3J0JHRheCA9IEdCSUZfZXhwb3J0JHRheFssY29sX29yZGVyXQoKCgppZiAoIWRpci5leGlzdHMoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL0dCSUYiKSkge2Rpci5jcmVhdGUoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL0dCSUYiLCByZWN1cnNpdmUgPSBUUlVFKX0Kd3JpdGUuY3N2KEdCSUZfZXhwb3J0JGFidW5kLCAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvR0JJRi9BU1ZUYWJsZS5jc3YiLCByb3cubmFtZXM9VFJVRSkKd3JpdGUuY3N2KEdCSUZfZXhwb3J0JHRheCwgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL0dCSUYvVGF4VGFibGUuY3N2Iiwgcm93Lm5hbWVzPVRSVUUpCndyaXRlLmNzdihHQklGX2V4cG9ydCRtZXRhZGF0YSwgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL0dCSUYvU2FtcGxlRGF0YS5jc3YiLCByb3cubmFtZXM9RkFMU0UpCgpgYGAKClRvIGVuc3VyZSB0aGUgYWNjdXJhY3kgb2YgdGF4b25vbWljIGFzc2lnbm1lbnRzLCB3ZSBhbmFseXplZCBvY2N1cnJlbmNlIGRhdGEgZnJvbSB0aGUgR2xvYmFsIEJpb2RpdmVyc2l0eSBJbmZvcm1hdGlvbiBGYWNpbGl0eSB0byBpbnZlc3RpZ2F0ZSB3aGV0aGVyIGlkZW50aWZpZWQgc3BlY2llcyBoYWQgb2NjdXJyZW5jZSByZWNvcmRzIGluIHRoZSBDYWxpZm9ybmlhIEN1cnJlbnQgU3lzdGVtIGFuZCBrbm93biByYW5nZXMgdGhhdCBlbmNvbXBhc3NlZCBQaWxsYXIgUG9pbnQsIHVzaW5nIHRoZSBgc3BvY2NgICh2ZXJzaW9uIGByIHBhY2thZ2VWZXJzaW9uKCJzcG9jYyIpYCBgcGFja2FnZVZlcnNpb24oInNwb2NjIilgKSAoQ2hhbWJlcmxhaW4sIDIwMjEpIHBhY2thZ2UuIEEgcGh5bG9nZW5ldGljIHRyZWUgYmFzZWQgb24gdGF4b25vbWljIGFzc2lnbm1lbnRzIHdhcyBjcmVhdGVkIHVzaW5nIHRoZSB0YXhpemUgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oInRheGl6ZSIpYCBgcGFja2FnZVZlcnNpb24oInRheGl6ZSIpYCkgKENoYW1iZXJsYWluIGFuZCBTesO2Y3MsIDIwMTMpIGFuZCBnZ3RyZWVFeHRyYSBgciBwYWNrYWdlVmVyc2lvbigiZ2d0cmVlRXh0cmEiKWAgYHBhY2thZ2VWZXJzaW9uKCJnZ3RyZWVFeHRyYSIpYCAoY2l0YXRpb24pIHBhY2thZ2VzLgoKIyMjIyBEYXRhIEFuYWx5c2lzCgpUbyB1bmRlcnN0YW5kIHdoZXRoZXIgZUROQSBzaWduYWxzIGNvdWxkIGJlIGRpc3Rpbmd1aXNoZWQgYnkgbG9jYXRpb24sIHdlIGZpcnN0IGFuYWx5emVkIGluZGl2aWR1YWwtbGV2ZWwgZGlmZmVyZW5jZXMgYmV0d2VlbiBsb2NhdGlvbnM7IHRoYXQgaXMsIHdoZXRoZXIgQVNWcyBvciBpbmRpdmlkdWFsIHRheGEgKGFnZ2xvbWVyYXRlZCBzcGVjaWVzLWxldmVsIHRheG9ub21pYyBhc3NpZ25tZW50cykgd2VyZSB1bmlxdWUgdG8sIG9yIGFzc29jaWF0ZWQgd2l0aCwgcGFydGljdWxhciBsb2NhdGlvbnMuIFdlIGNhbGN1bGF0ZWQgYW5kIHZpc3VhbGl6ZWQgdW5pcXVlIEFTVnMgYW5kIHRheGEgdXNpbmcgdGhlIGBldWxlcnJgICh2ZXJzaW9uIGByIHBhY2thZ2VWZXJzaW9uKCJldWxlcnIiKWAgYHBhY2thZ2VWZXJzaW9uKCJldWxlcnIiKWApIChMYXJzc29uLCAyMDIyKSBwYWNrYWdlLiBIb3dldmVyLCB3aXRoIG1ldGFiYXJjb2RpbmcgZGF0YSBpbiBwYXJ0aWN1bGFyLCB0YXhhIG9yIEFTVnMgdGhhdCBhcmUgdW5pcXVlIHRvIGEgZ2l2ZW4gbG9jYXRpb24gYXJlIG5vdCBuZWNlc3NhcmlseSBlY29sb2dpY2FsbHkgbWVhbmluZ2Z1bDsgdGhleSBjb3VsZCBpbmNsdWRlIHJhcmUgdGF4YSBwcmVzZW50IGVsc2V3aGVyZSBidXQgbm90IGFtcGxpZmllZCBhbmQgZXhjbHVkZSB0YXhhIHRoYXQgYXJlIHdlbGwgY29ycmVsYXRlZCB3aXRoIHBhcnRpY3VsYXIgbG9jYXRpb25zIGJ1dCBzb21ldGltZXMgZGV0ZWN0ZWQgYXQgb3RoZXJzLiBUaHVzLCB3ZSBhbHNvIGFuYWx5emVkIEFTVnMgYW5kIHRheGEgdXNpbmcgYW4gaW5kaWNhdG9yIHNwZWNpZXMgZnJhbWV3b3JrIChEdWZyw6puZSBhbmQgTGVnZW5kcmUsIDE5OTcpLiBJbiB0aGlzIGZyYW1ld29yaywgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSBmcmVxdWVuY3kgb2YgYSB0YXhvbidzIG9yIEFTVidzIHByZXNlbmNlIGluIHNhbXBsZXMgZnJvbSBhIHBhcnRpY3VsYXIgbG9jYXRpb24gaXMgbm90IGhpZ2hlciB0aGF0IHRoZSBmcmVxdWVuY3kgb2YgdGhhdCB0YXhvbidzIG9yIEFTVidzIHByZXNlbmNlIGluIHNhbXBsZXMgZnJvbSBvdGhlciBsb2NhdGlvbnMuIEZvciBlYWNoIGxvY2F0aW9uLCB3ZSBpZGVudGlmaWVkIGFsbCBzdGF0aXN0aWNhbGx5LXNpZ25pZmljYW50IGluZGljYXRvciB0YXhhIGFuZCBBU1ZzIHdpdGggaW5kaWNhdG9yIHZhbHVlIGluZGljZXMgYWJvdmUgMC43LS0tdGhhdCBpcywgaW5kaWNhdG9ycyB0aGF0IGFyZSB3ZWxsLWFzc29jaWF0ZWQgd2l0aCBhIHNpdGUgZ3JvdXAgZXZlbiBpZiB0aGV5IGFyZSBkZXRlY3RlZCBpbiBzYW1wbGVzIGZyb20gb3RoZXIgc2l0ZXMtLS1iYXNlZCBvbiBwcmVzZW5jZS1hYnNlbmNlIGRhdGEgcGVyIHNhbXBsZSB1c2luZyB0aGUgYGluZGljc3BlY2llc2AgcGFja2FnZSAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigiaW5kaWNzcGVjaWVzIilgIGBwYWNrYWdlVmVyc2lvbigiaW5kaWNzcGVjaWVzIilgKSAoQ8OhY2VyZXMgYW5kIExlZ2VuZHJlLCAyMDA5KS4KCldlIGZvbGxvd2VkIG91ciBpbmRpdmlkdWFsLWxldmVsIGFuYWx5c2VzIHdpdGggYXBwcm9hY2hlcyB0byB0ZXN0IHdoZXRoZXIgY29tbXVuaXR5IGNvbXBvc2l0aW9uIHZhcmllZCBieSBsb2NhdGlvbi4gV2UgY2FsY3VsYXRlZCBhIEphY2NhcmQgZGlzc2ltaWxhcml0eSBtYXRyaXggYWNyb3NzIGFsbCBzYW1wbGVzIHVzaW5nIGB2ZWdhbmAgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oInZlZ2FuIilgIGBwYWNrYWdlVmVyc2lvbigidmVnYW4iKWApIChPa3NhbmVuIGV0IGFsLiwgMjAyMikuIFRoZW4sIHdlIHRlc3RlZCBmb3IgZGlmZmVyZW5jZXMgaW4gY29tbXVuaXR5IGNvbXBvc2l0aW9uIGFtb25nIGxvY2F0aW9ucyB1c2luZyBhIHBlcm11dGF0aW9uYWwgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIG9mIHZhcmlhbmNlIChQRVJNQU5PVkEpIHdpdGggdGhlIG1vZGVsIGVETkEgUHJlc2VuY2UgXH4gTG9jYXRpb24gKyBUaW1lICsgQmlvbG9naWNhbCBSZXBsaWNhdGVzIHVzaW5nIHRoZSBgYWRvbmlzYCBmdW5jdGlvbiBpbiBgdmVnYW5gLiBXZSBjb25maXJtZWQgdGhhdCBsb2NhdGlvbmFsIGRpZmZlcmVuY2VzIGZvdW5kIHZpYSBQRVJNQU5PVkEgd2VyZSBub3QgYSByZXN1bHQgb2YgZGlmZmVyZW5jZXMgaW4gZGlzcGVyc2lvbnMgYnkgdGVzdGluZyBmb3IgaG9tb2dlbmVpdHkgb2YgZGlzcGVyc2lvbnMgdXNpbmcgdGhlIGBiZXRhZGlzcGVyYCBmdW5jdGlvbiBpbiBgdmVnYW5gLiBXZSBhbHNvIHZpc3VhbGl6ZWQgSmFjY2FyZCBkaXNzaW1pbGFyaXR5IHVzaW5nIG5vbi1tZXRyaWMgbXVsdGlkaW1lbnNpb25hbCBzY2FsaW5nIChOTURTKSB1c2luZyB0aGUgYG1ldGFNRFNgIGZ1bmN0aW9uIGluIGB2ZWdhbmAuIFdlIGNvdXBsZWQgdGhlc2UgYW5hbHlzZXMgd2l0aCBhIHBhcnRpdGlvbmluZyBhbW9uZyBtZWRvaWRzIGFsZ29yaXRobSAoS2F1Zm1hbiBhbmQgUm91c3NlZXV3LCAxOTkwKSBpbXBsZW1lbnRlZCB3aXRoIHRoZSBgcGFtYCBmdW5jdGlvbiBpbiB0aGUgYGNsdXN0ZXJgIHBhY2thZ2UgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oImNsdXN0ZXIiKWAgYHBhY2thZ2VWZXJzaW9uKCJjbHVzdGVyIilgKSAoTWFlY2hsZXIgZXQgYWwuLCAyMDIyKS4gUmF0aGVyIHRoYW4gYXNzdW1pbmcgbG9jYXRpb24gY2x1c3RlcnMgYSBwcmlvcmksIHdlIHZhbGlkYXRlZCB0aGUgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMgZm9yIGEgZ2l2ZW4gZGF0YXNldCBieSBmaW5kaW5nIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMgKGspIHRoYXQgbWF4aW1pemVkIHRoZSBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGgsIGEgbWVhc3VyZSBvZiBob3cgd2VsbC1zdHJ1Y3R1cmVkIHRoZSBjbHVzdGVycyBhcmUuIEZpbmFsbHksIHRvIGJldHRlciB1bmRlcnN0YW5kIGhvdyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGxvY2F0aW9ucyB2YXJpZWQgb3ZlciB0aGUgdGltZSBzYW1wbGVkLCBmb3IgZWFjaCB0aW1lIHBvaW50LCB3ZSBjYWxjdWxhdGVkIHRoZSBKYWNjYXJkIGRpc3NpbWlsYXJpdHkgYmV0d2VlbiBlYWNoIHVuaXF1ZSBjb21iaW5hdGlvbiBvZiByZXBsaWNhdGVzIHdpdGhpbiBlYWNoIHNpdGUsIGFuZCB0aGVuIHRoZSBwYWlyd2lzZSBKYWNjYXJkIGRpc3NpbWlsYXJpdHkgYmV0d2VlbiBlYWNoIHVuaXF1ZSBjb21iaW5hdGlvbiBvZiBzYW1wbGVzIGFjcm9zcyB0aGUgdGhyZWUgcGFpcnMgb2Ygc2l0ZXM6IFMxLU4sIFMyLU4sIGFuZCBTMS1TMi4KClRvIGZ1cnRoZXIgdW5kZXJzdGFuZCB3aGV0aGVyIGRpZmZlcmVuY2VzIGluIGVETkEgZGV0ZWN0aW9ucyBjb3JyZXNwb25kZWQgd2l0aCB1bmRlcmx5aW5nIGVjb2xvZ2ljYWwgZ3JhZGllbnRzLCB3ZSBjb21wYXJlZCB0aGUgdW5pcXVlIGFuZCBpbmRpY2F0b3IgdGF4YSBpZGVudGlmaWVkIGF0IGVhY2ggc2l0ZSB0byB0aGVpciBlY29sb2dpY2FsIHpvbmF0aW9uIGluIGEgaGlnaGx5IHJlZ2FyZGVkIGZpZWxkIGd1aWRlIHRvIHRoZSBQYWNpZmljIGludGVydGlkYWwsIEJldHdlZW4gUGFjaWZpYyBUaWRlcyAoUmlja2V0dHMgZXQgYWwuLCAxOTg1KS4gVG8gYWNjb3VudCBmb3IgcG90ZW50aWFsIHZhcmlhdGlvbnMgaW4gdGF4b25vbWljIG5hbWVzIGJldHdlZW4gQmV0d2VlbiBQYWNpZmljIFRpZGVzIGFuZCB0aGUgTUlET1JJMiByZWZlcmVuY2UgZGF0YWJhc2UsIHdlIHVzZWQgdGhlIFdvcmxkIFJlZ2lzdGVyIG9mIE1hcmluZSBTcGVjaWVzIChXb1JNUykgdG8gaWRlbnRpZnkgYWxsIHN5bm9ueW1pemVkIG5hbWVzIGZvciBlYWNoIHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHRheG9uIGlkZW50aWZpZWQsIGFuZCB3ZSBzZWFyY2hlZCBCZXR3ZWVuIFBhY2lmaWMgVGlkZXMgZm9yIGFsbCBzeW5vbnltcy4gV2UgY29tcGFyZWQgdGhlIHByb3BvcnRpb24gb2YgaGlnaCBhbmQgbWlkZGxlIGludGVydGlkYWwgc3BlY2llcyBpZGVudGlmaWVkIGFjcm9zcyBlYWNoIGxvY2F0aW9uIHVzaW5nIGEgY2hpLXNxdWFyZWQgdGVzdCB3aXRoIHAtdmFsdWVzIGNvbXB1dGVkIHZpYSBNb250ZSBDYXJsbyBzaW11bGF0aW9uLgoKIyMjIFJlc3VsdHMKCiMjIyMgMy4xIFNlcXVlbmNpbmcgUmVzdWx0cyAmIFRheG9ub21pYyBEaXZlcnNpdHkKCmBgYHtyLCBGdWxsIE91dHB1dCBNZXRyaWNzfQojIyNGdWxsIE91dHB1dCBNZXRyaWNzIyMjCiNHZW5lcmF0ZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZnVsbCBBbmFjYXBhIFBpcGVsaW5lIHJlc3VsdHMKCiNHYXRoZXIgaW5mb3JtYXRpb24gYWJvdXQgZnVsbCBBbmFjYXBhIFBpcGVsaW5lIHJlc3VsdHMgYmVmb3JlIGFueSBwcm9jZXNzaW5nCnRvdGFsX0FTVnMgPSBucm93KGFtcCRhYnVuZCkKdG90YWxfcmVhZHMgPSBzdW0oYW1wJGFidW5kKQoKc2FtcGxlcyA9IGxlbmd0aChhbXAkbWV0YWRhdGEkVHlwZVthbXAkbWV0YWRhdGEkVHlwZSA9PSAic2FtcGxlIl0pCmNvbnRyb2xzID0gbGVuZ3RoKGFtcCRtZXRhZGF0YSRUeXBlW2FtcCRtZXRhZGF0YSRUeXBlID09ICJjb250cm9sIl0pCgojQ2hlY2sgcG9zaXRpdmUgUENSIGNvbnRyb2xzCmFtcF9NQyA9IGFtcF9maWx0ZXJfc2FtcGxlcyhhbXAsIExvY2F0aW9uICVpbiUgYygiTUMiKSkKCmRmID0gbWVyZ2UoYW1wX01DJGFidW5kLCBhbXBfTUMkdGF4LCBieSA9ICdyb3cubmFtZXMnKQpkZiA9IGRmWyxjKDI6MywgMTApXQpjb2xuYW1lcyhkZikgPSBjKCJNQzEiLCAiTUMyIiwgIlNwZWNpZXMiKQphZ2dfZGYgPC0gZGYgJT4lIGdyb3VwX2J5KFNwZWNpZXMpICU+JSBzdW1tYXJpc2UoTUMxX1JlYWRzID0gc3VtKE1DMSksIE1DMl9SZWFkcyA9IHN1bShNQzIpKSAlPiUgYXJyYW5nZShkZXNjKE1DMV9SZWFkcykpCmFnZ19kZlthZ2dfZGYgPT0gIiJdID0gIk5vIFRheG9ub21pYyBBc3NpZ25tZW50IgphZ2dfZGYkU3BlY2llcyA9IHJlbW92ZV9OQ0JJbnVtcyhhZ2dfZGYkU3BlY2llcykKYWdnX2RmCgphbXBfbm9fTUMgPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wLCAhKExvY2F0aW9uICVpbiUgYygiTUMiKSkpCgppZiAobGVuZ3RoKGludGVyc2VjdChyb3duYW1lcyhhbXBfTUMkYWJ1bmQpLCByb3duYW1lcyhhbXBfbm9fTUMkYWJ1bmQpKSkgPT0gMCkgewogIE1DX292ZXJsYXAgPSAibm8gQVNWcyBwcmVzZW50IGluIHRoZSBwb3NpdGl2ZSBQQ1IgY29udHJvbHMgb2NjdXJyZWQgaW4gYW55IG90aGVyIHNhbXBsZXMsIHByb3ZpZGluZyBubyBldmlkZW5jZSBvZiBpbmRleCBob3BwaW5nIgp9IGVsc2UgewogIE1DX292ZXJsYXAgPSAic29tZSBBU1ZzIHByZXNlbnQgaW4gdGhlIHBvc2l0aXZlIFBDUiBjb250cm9scyBvY2N1cnJlZCBpbiBvdGhlciBzYW1wbGVzLCBwcm92aWRpbmcgZXZpZGVuY2Ugb2YgaW5kZXggaG9wcGluZyAoQ0hFQ0sgVEhJUykiCn0KCiNDaGVjayBpbnRlcnNlY3Rpb24gYmV0d2VlbiBzYW1wbGVzIGFuZCBjb250cm9scwppbnRlcnNlY3QgPSBpbnRlcnNlY3Qocm93bmFtZXMoYW1wX2NvbnRyb2xzJGFidW5kKSwgcm93bmFtZXMoYW1wX25vY29udHJvbHMkYWJ1bmQpKQpvdmVybGFwID0gbGVuZ3RoKGludGVyc2VjdCkKCm92ZXJsYXBfdGFibGUgPSBkYXRhLmZyYW1lKEFTViA9IGludGVyc2VjdCwgIlRheG9ub21pYyBBc3NpZ25tZW50IiA9IGFtcF9ub2NvbnRyb2xzJHRheFthbXBfbm9jb250cm9scyR0YXgkT1RVICVpbiUgaW50ZXJzZWN0LF0kU3BlY2llcykKb3ZlcmxhcF90YWJsZSRUYXhvbm9taWMuQXNzaWdubWVudCA9IHJlbW92ZV9OQ0JJbnVtcyhvdmVybGFwX3RhYmxlJFRheG9ub21pYy5Bc3NpZ25tZW50KQpvdmVybGFwX3RhYmxlCmBgYAoKVXNpbmcgdGhlIEFuYWNhcGEgVG9vbGtpdCwgd2UgaWRlbnRpZmllZCBgciB0b3RhbF9BU1ZzYCAoYHRvdGFsX0FTVnNgKSBBU1ZzIGZyb20gYHIgdG90YWxfcmVhZHNgKGB0b3RhbF9yZWFkc2ApIHJlYWRzIGFjcm9zcyBgciBzYW1wbGVzYCAoYHNhbXBsZXNgKSBzYW1wbGVzIGFuZCBgciBjb250cm9sc2AgKGBjb250cm9sc2ApIGNvbnRyb2xzIChwb3NpdGl2ZSBQQ1IgY29udHJvbHMsIG5lZ2F0aXZlIGZpZWxkIGNvbnRyb2xzLCBuZWdhdGl2ZSBleHRyYWN0aW9uIGNvbnRyb2xzLCBhbmQgbm8tdGVtcGxhdGUgbmVnYXRpdmUgUENSIGNvbnRyb2xzKS4gQWxsIGV4cGVjdGVkIHRheGEgYW1wbGlmaWVkIGluIGVhY2ggcG9zaXRpdmUgUENSIGNvbnRyb2wsIGFuZCBgciBNQ19vdmVybGFwYCAoYE1DX292ZXJsYXBgKS4gQmVmb3JlIGFwcGxpY2F0aW9uIG9mIGFueSBkZWNvbnRhbWluYXRpb24gc3RlcHMsIG9ubHkgYHIgb3ZlcmxhcGAgKGBvdmVybGFwYCkgQVNWcyB3ZXJlIHNoYXJlZCBiZXR3ZWVuIHRoZSBzYW1wbGVzIGFuZCBuZWdhdGl2ZSBmaWVsZCwgZXh0cmFjdGlvbiwgYW5kIFBDUiBjb250cm9scy4KCmBgYHtyLCBDb3JlIERhdGEgU2V0c30KIyMjQ29yZSBEYXRhIFNldHMjIyMKI0VzdGFibGlzaCBwcm9jZXNzZWQgZGF0YSBzZXQgdXNlZCB0aHJvdWdob3V0IGFuYWx5c2VzCgpkYXRhX2FtcCA9IGFtcF9ub2NvbnRyb2xzX05TX0ZEX1IKCmRhdGFfcGh5c2VxID0gYW1wX3RvX3BoeWxvc2VxKGRhdGFfYW1wLCBOVUxMLCBOVUxMLCBOVUxMKQoKZGF0YV9hbXBfdGF4YSA9IGRhdGFfYW1wCmRhdGFfYW1wX3RheGEkYWJ1bmQgPSBhZ2dyZWdhdGVfYWJ1bmQoZGF0YV9hbXAkYWJ1bmQsIGRhdGFfYW1wJHRheCwgdGF4X2FnZ3JlZ2F0ZSA9ICJTcGVjaWVzIiwgZm9ybWF0ID0gImFidW5kIikKCgppZiAoIWRpci5leGlzdHMoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMiKSkge2Rpci5jcmVhdGUoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMiLCByZWN1cnNpdmUgPSBUUlVFKX0Kd3JpdGUuY3N2KGRhdGFfYW1wJGFidW5kLCAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTWFudXNjcmlwdCBBbmFseXNpcy9BU1ZUYWJsZS5jc3YiLCByb3cubmFtZXM9VFJVRSkKd3JpdGUuY3N2KGRhdGFfYW1wJHRheCwgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMvVGF4VGFibGUuY3N2Iiwgcm93Lm5hbWVzPVRSVUUpCndyaXRlLmNzdihkYXRhX2FtcCRtZXRhZGF0YSwgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMvU2FtcGxlRGF0YS5jc3YiLCByb3cubmFtZXM9RkFMU0UpCgpgYGAKCmBgYHtyLCBGaWd1cmUgMyAtLUNvbnRpbnVlZCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgZmlnLndpZHRoPSAxNjksIGZpZy5oZWlnaHQgPSAyMDB9CiMjI0ZpZ3VyZSAzLS1Db250aW51ZWQjIyMKI0ZpbmlzaCB0aGUgYm90dG9tIHBvcnRpb24gb2YgRmlndXJlIDMgbm93IHRoYXQgZGF0YSBoYXMgYmVlbiBsb2FkZWQKCmRhdGFfZm9yY2hhcnQgPSBhbXAkbWV0YWRhdGFbIWlzLm5hKGFtcCRtZXRhZGF0YSRUaW1lKSxdCgpkYXRhX2ZvcmNoYXJ0ID0gZGF0YV9mb3JjaGFydCAlPiUgZ3JvdXBfYnkoU2l0ZUJ5VGltZSkgJT4lIG11dGF0ZShjaGFydF9udW0gPSBjZWlsaW5nKHJvd19udW1iZXIoKS8zKSkKCmZhY2V0LmxhYnMgPSAgYygiVGlkZSBQb29sIDFcbiAoUzEpIiwgIlRpZGUgUG9vbCAyXG4gKFMyKSIsICJOZWFyc2hvcmVcbiAoTikiLCAiRmllbGQgQmxhbmsiKQpuYW1lcyhmYWNldC5sYWJzKSA9IGMoIlMxIiwgIlMyIiwgIk4iLCAiRkIiKQoKZGF0YV9mb3JjaGFydCRMb2NhdGlvbj0gZmFjdG9yKGRhdGFfZm9yY2hhcnQkTG9jYXRpb24sIGxldmVscz1jKCJTMSIsICJTMiIsICJOIiwgIkZCIikpCmRhdGFfZm9yY2hhcnQkY2hhcnRfbnVtPSBmYWN0b3IoZGF0YV9mb3JjaGFydCRjaGFydF9udW0sIGxldmVscz1jKCIzIiwgIjIiLCAiMSIpKQoKc2FtcGxlX3NjaGVtYSA9IGdncGxvdChkYXRhID0gZGF0YV9mb3JjaGFydCwgYWVzKHggPSBUaW1lLCB5ID0gY2hhcnRfbnVtLCBzaGFwZSA9IExvY2F0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFRpbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gYWZ0ZXJfc2NhbGUoYWxwaGEoY29sb3VyLCAwLjA1KSkpKSArIAogIGdlb21fYmVlc3dhcm0oY2V4ID0gMiwgc2l6ZSA9IDMpICsgCiAgZ2VvbV9ib3goYWVzKHhtaW4gPSBhZnRlcl9zdGF0KHgpIC0gMC40NSwgCiAgICAgICAgICAgICAgIHhtYXggPSBhZnRlcl9zdGF0KHgpICsgMC40NSwKICAgICAgICAgICAgICAgeW1pbiA9IGFmdGVyX3N0YXQoeSkgLSAwLjQ1LCAKICAgICAgICAgICAgICAgeW1heCA9IGFmdGVyX3N0YXQoeSkgKyAwLjQ1KSwKICAgICAgICAgICByYWRpdXMgPSB1bml0KDUsICJwdCIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTUsIDE3LCAxNiwgMTgpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChkaXJlY3Rpb24gPSAtMSwgYmVnaW4gPSAwLCBlbmQgPSAuOTcpICsKICBmYWNldF9ncmlkKExvY2F0aW9uIH4uLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IiwgCiAgICAgICAgICAgICBzd2l0Y2ggPSAieSIsIGxhYmVsbGVyID0gbGFiZWxsZXIoTG9jYXRpb24gPSBmYWNldC5sYWJzKSkgKwogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMTIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLCB2anVzdCA9IC45KSwKICAgICAgICBwbG90Lm1hcmdpbj1tYXJnaW4oMCwwLDAsMCwgInB0IikpICAKCgpjb21iaW5lZCA9IChwbG90X3NwYWNlcigpICsgcF9wYXRjaCArIHBsb3Rfc3BhY2VyKCkgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDMsNTAsMSkpKS8ocGxvdF9zcGFjZXIoKSArIHNhbXBsZV9zY2hlbWEgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsNTApKSkgJiB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMCwwLDAsMCwgInB0IikpCgoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTNfZnVsbC4iCnNhdmVfcGRmX3BuZyhwbG90ID0gY29tYmluZWQsIHBhdGggPSBwYXRoLCB3ID0gMTY5LCBoID0gMTY5LCB1ID0gIm1tIiwgYmcgPSAidHJhbnNwYXJlbnQiLCBkcGkgPSA2MDApCgpgYGAKCjxjZW50ZXI+CgohWypGaWd1cmUgMzogR3JhcGggb2YgdGlkZSBwcmVkaWN0aW9ucyBkdXJpbmcgZmllbGQgc2FtcGxpbmcgb24gMjggSmFudWFyeSAyMDIyLCB3aXRoIGljb25zIHRvIGluZGljYXRlIHRoZSBzYW1wbGluZyBzY2hlbWUqXShgciBwYXN0ZTAocGF0aCwgInBuZyIpYCkKCjwvY2VudGVyPgoKYGBge3IsIFByb2Nlc3NlZCBPdXRwdXQgTWV0cmljc30KIyMjUHJvY2Vzc2VkIE91dHB1dCBNZXRyaWNzIyMjCiNHYXRoZXIgaW5mb3JtYXRpb24gYWJvdXQgcHJvY2Vzc2VkIEFuYWNhcGEgVG9vbGtpdCAKCnByb2Nlc3NlZF9BU1ZzID0gbnJvdyhkYXRhX2FtcCRhYnVuZCkKcHJvY2Vzc2VkX3JlYWRzID0gc3VtKGRhdGFfYW1wJGFidW5kKQoKI0NyZWF0ZSBhIHBoeWxvc2VxIG9iamVjdCB3aGVyZSBhbGwgc2FtcGxlcyBhcmUgY29tYmluZWQgaW50byBvbmUKdG90YWwgPSBhcy5kYXRhLmZyYW1lKHJvd1N1bXMoZGF0YV9hbXAkYWJ1bmQpKQpwaHlzZXFfc3VtbWVkID0gYW1wX3RvX3BoeWxvc2VxKE5VTEwsIHRvdGFsLCBkYXRhX2FtcCR0YXhbLDE6N10sIE5VTEwpCiAgCiNTdW1tYXJpemUgdGhlIG51bWJlciBvZiB1bmFzc2lnbmVkIEFTVnMKa2luZ2RvbSA9IGFzLmRhdGEuZnJhbWUodGF4X3RhYmxlKHBoeXNlcV9zdW1tZWQpWywxXSkKdW5hc3NpZ25lZF9BU1ZzID0ga2luZ2RvbSAlPiUgZ3JvdXBfYnkoS2luZ2RvbSkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgbXV0YXRlIChmcmVxID0gbiAvIHN1bShuKSkKCiNTdW1tYXJpemUgbnVtYmVyIG9mIHVuaXF1ZSB0YXhhIGF0IGVhY2ggdGF4b25vbWljIGxldmVsCnVuaXF1ZSA9IGFwcGx5KHRheF90YWJsZShwaHlzZXFfc3VtbWVkKSwgMiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHVuaXF1ZSh4W3ggIT0gIiJdKSkpCgogIApgYGAKCmBgYHtyLCBHQklGIFNldC1VcCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMjI0dCSUYgU2V0LVVwIyMjCiNDcmVhdGUgZnVuY3Rpb25zIGFuZCBkYXRhc2V0cyBuZWVkZWQgZm9yIEdCSUYgYW5hbHlzaXMKCiNDcmVhdGUgbGlzdCBvZiBpZGVudGlmaWVkIHNwZWNpZXMKc3BlY2llc19saXN0ID0gdW5pcXVlKGRhdGFfYW1wJHRheCRTcGVjaWVzKQpzcGVjaWVzX2xpc3QgPSByZW1vdmVfTkNCSW51bXMoc3BlY2llc19saXN0KQpzcGVjaWVzX2xpc3QgPSBzcGVjaWVzX2xpc3Rbc3BlY2llc19saXN0ICE9ICIiXQpzcGVjaWVzX2xpc3QgPSBzdWIoIl8iLCAiLSIsIHNwZWNpZXNfbGlzdCkgI3RvIGFkZHJlc3MgUHNldWRvX25pdHpjaGlhIGVycm9yCgojU3RhbmRhcmRpemUgc3BlY2llcyBuYW1lcyBhZ2FpbnN0IEdCSUYgYmFja2JvbmUKc3BlY2llc19HQklGID0gbmFtZV9iYWNrYm9uZV9jaGVja2xpc3Qoc3BlY2llc19saXN0KQpzcGVjaWVzX3N0YW5kYXJkaXplZCA9IHNwZWNpZXNfR0JJRiRzcGVjaWVzWyFpcy5uYShzcGVjaWVzX0dCSUYkc3BlY2llcyldCnNwZWNpZXNfYm90aCA9IHNwZWNpZXNfR0JJRltjKCJzcGVjaWVzIiwgInZlcmJhdGltX25hbWUiKV0KCiMjQ29yZSBHQklGIGNoZWNraW5nIGZ1bmN0aW9uCmRpc3RyaWJ1dGlvbl9jaGVjayA8LSBmdW5jdGlvbihzbWFsbF9ib3VuZCwgYmlnX2JvdW5kLCBzcGVjaWVzLCBtaW5fcmVjb3JkcywgZWZmaWNpZW5jeSkgewogIAogICMjRnVuY3Rpb24gdGhhdCBjaGVja3MgR0JJRiBnaXZlbiBhIHBhcnRpY3VsYXIgZ2VvZ3JhcGhpYyByZWdpb24KICBib3VuZGFyeV9mdW5jdGlvbiA8LSBmdW5jdGlvbihzcGVjaWVzLCBib3VuZHMpIHsKICAgIG5vX2RhdGEgPSBjKCkKICAgIGNvbmZpcm1lZCA9IGMoKQogICAgZm9yIChpIGluIHNwZWNpZXMpIHsKICAgICAgcHJpbnQoaSkKICAgICAgb2NjID0gb2NjKHF1ZXJ5ID0gaSwgCiAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IGJvdW5kcywgCiAgICAgICAgICAgICAgICBmcm9tID0gJ2diaWYnLCAKICAgICAgICAgICAgICAgIGxpbWl0ID0gbWluX3JlY29yZHMsIAogICAgICAgICAgICAgICAgaGFzX2Nvb3JkcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgZ2JpZm9wdHMgPSBsaXN0KGhhc0dlb3NwYXRpYWxJc3N1ZSA9IEZBTFNFKSkKICAgICAgb2NjLmRmID0gb2NjMmRmKG9jYykKICAgICAgaWYgKG5yb3cob2NjLmRmKSA+PSBtaW5fcmVjb3JkcykgeyAKICAgICAgICBjb25maXJtZWQgPSBhcHBlbmQoY29uZmlybWVkLCBpKQogICAgICB9IGVsc2UgewogICAgICAgIG5vX2RhdGEgPSBhcHBlbmQobm9fZGF0YSwgaSkKICAgICAgfQogICAgfQogICAgcmV0dXJuKGxpc3Qobm9fZGF0YSA9IG5vX2RhdGEsIGNvbmZpcm1lZCA9IGNvbmZpcm1lZCkpCiAgfQogIAogICMjRnVuY3Rpb24gdGhhdCBjaGVja3MgR0JJRiB0byBjb25maXJtIHdoZXRoZXIgYSBwYXJ0aWN1bGFyIGxvY2F0aW9uIGlzIHdpdGhpbiB0aGUgcmFuZ2Ugb2Ygb2JzZXJ2YXRpb25zCiAgcmFuZ2VfZnVuY3Rpb24gPC0gZnVuY3Rpb24oc3BlY2llcyl7CiAgICBDQy5jb25maXJtZWQgPSBjKCkKICAgIENDLm5vdF9jb25maXJtZWQgPSBjKCkKICAgIENDLm5vX2RhdGEgPSBjKCkgCiAgICBsaW1pdHMgPSBjKDEwLCAxMDAsIDEwMDAsIDEwMDAwKQogICAgCiAgICBmb3IgKGkgaW4gc3BlY2llcykgewogICAgICB0cmFjayA9IDAKICAgICAgZm9yIChsIGluIGxpbWl0cykgewogICAgICAgIHByaW50KGkpCiAgICAgICAgcHJpbnQgKGwpCiAgICAgICAgb2NjID0gb2NjKGksIGZyb20gPSAnZ2JpZicsIGxpbWl0ID0gbCwgaGFzX2Nvb3JkcyA9IFRSVUUsIGdiaWZvcHRzID0gbGlzdChoYXNHZW9zcGF0aWFsSXNzdWUgPSBGQUxTRSkpCiAgICAgICAgb2NjLmRmID0gb2NjMmRmKG9jYykKICAgICAgICBpZiAobnJvdyhvY2MuZGYpIDwgbWluX3JlY29yZHMpIHsKICAgICAgICAgIENDLm5vX2RhdGEgPSBhcHBlbmQoQ0Mubm9fZGF0YSwgaSkKICAgICAgICAgIHByaW50KCJubyBkYXRhIikKICAgICAgICAgIHRyYWNrID0gMQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgYmJfb2NjID0gc3A6OmJib3goY2JpbmQob2NjLmRmJGxvbmdpdHVkZSwgb2NjLmRmJGxhdGl0dWRlKSkKICAgICAgICBpZiAoYmJfb2NjWyd4JywgJ21pbiddIDwgc21hbGxfYm91bmRbMV0gJiAKICAgICAgICAgICAgYmJfb2NjWyd4JywgJ21heCddID5zbWFsbF9ib3VuZFsxXSAmIAogICAgICAgICAgICBiYl9vY2NbJ3knLCAnbWluJ10gPHNtYWxsX2JvdW5kWzRdICYgCiAgICAgICAgICAgIGJiX29jY1sneScsICdtYXgnXSA+c21hbGxfYm91bmRbNF0pIHsKICAgICAgICAgIENDLmNvbmZpcm1lZCA9IGFwcGVuZChDQy5jb25maXJtZWQsIGkpCiAgICAgICAgICBwcmludCgiY29uZmlybWVkIikKICAgICAgICAgIHRyYWNrID0gMQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgICAgaWYobnJvdyhvY2MuZGYpIDwgbCkgewogICAgICAgICAgQ0Mubm90X2NvbmZpcm1lZCA9IGFwcGVuZChDQy5ub3RfY29uZmlybWVkLCBpKQogICAgICAgICAgcHJpbnQoIm5vdCBjb25maXJtZWQiKQogICAgICAgICAgdHJhY2sgPSAxCiAgICAgICAgICBicmVhawogICAgICAgIH0gCiAgICAgIH0KICAgICAgaWYodHJhY2sgPT0gMCkgewogICAgICAgIENDLm5vdF9jb25maXJtZWQgPSBhcHBlbmQoQ0Mubm90X2NvbmZpcm1lZCwgaSkKICAgICAgICBwcmludCgibm90IGNvbmZpcm1lZCIpCiAgICAgIH0KICAgIH0KICAgIHJldHVybihsaXN0KG5vX2RhdGEgPSBDQy5ub19kYXRhLCBub3RfY29uZmlybWVkID0gQ0Mubm90X2NvbmZpcm1lZCwgY29uZmlybWVkID0gQ0MuY29uZmlybWVkKSkKICB9CiAgCiAgCiAgI0FjdHVhbCBTdGVwcwogIFBQID0gYm91bmRhcnlfZnVuY3Rpb24oc3BlY2llcywgc21hbGxfYm91bmQpCiAgCiAgaWYoZWZmaWNpZW5jeSA9PSBUUlVFKSB7CiAgICBDQyA9IGJvdW5kYXJ5X2Z1bmN0aW9uKFBQW1sibm9fZGF0YSJdXSwgYmlnX2JvdW5kKQogIH0gZWxzZSB7CiAgICBDQyA9IGJvdW5kYXJ5X2Z1bmN0aW9uKHNwZWNpZXMsIGJpZ19ib3VuZCkKICB9CiAgCiAgaWYoZWZmaWNpZW5jeSA9PSBUUlVFKSB7CiAgICByYW5nZV9jb25maXJtZWQgPSByYW5nZV9mdW5jdGlvbihDQ1tbImNvbmZpcm1lZCJdXSkKICAgIHJhbmdlX3VuY29uZmlybWVkID0gcmFuZ2VfZnVuY3Rpb24oQ0NbWyJub3RfY29uZmlybWVkIl1dKQogICAgcmV0dXJuKGxpc3QoUFAsIENDLCByYW5nZV9jb25maXJtZWQsIHJhbmdlX3VuY29uZmlybWVkKSkKICB9IGVsc2UgewogICAgcmFuZ2UgPSByYW5nZV9mdW5jdGlvbihzcGVjaWVzKQogICAgcmV0dXJuKGxpc3QoUFAsIENDLCByYW5nZSkpCiAgfQp9CgojR2V0IHRoZSBDYWxpZm9ybmlhIEN1cnJlbnQgU3lzdGVtIHNoYXBlCgpDQ19zaGFwZSA9IG1yX2ZlYXR1cmVzX2dldCh0eXBlID0gIk1hcmluZVJlZ2lvbnM6bG1lIiwgZmVhdHVyZUlEID0gImxtZS4xMCIsIGZvcm1hdCA9ICJqc29uIikKCiNjaGVjayB0aGF0IGl0J3MgdGhlIHJpZ2h0IHBvbHlnb24KY2xhc3MoQ0Nfc2hhcGUpIDwtICJtcl9nZW9qc29uIgpDQ19zaGFwZSA9IG1yX2FzX3drdChDQ19zaGFwZSkKcG50IDwtIHN0X2FzX3NmYyhDQ19zaGFwZSwgY3JzID0gNDMyNikKbWFwdmlldyhwbnQpCgojU2ltcGxpZnkgdGhlIHBvbHlnb24gZm9yIHVzZSB3aXRoIEdCSUYKQ0Nfc2hhcGVfc3AgPSBzdF90cmFuc2Zvcm0ocG50LCBjcnMgPSAnK3Byb2o9YWVxZCArbGF0XzA9NTMuNiArbG9uXzA9MTIuNycpCm1hcHZpZXcoQ0Nfc2hhcGVfc3ApCkNDX3NoYXBlX3NwID0gc3Rfc2ltcGxpZnkoQ0Nfc2hhcGVfc3AsIHByZXNlcnZlVG9wb2xvZ3kgPSBGQUxTRSwgZFRvbGVyYW5jZT0xMDAwMCkKQ0Nfc2hhcGVfc3AgPSBzdF90cmFuc2Zvcm0oQ0Nfc2hhcGVfc3AsIGNycyA9IDQzMjYpCm1hcHZpZXcoQ0Nfc2hhcGVfc3ApCgpgYGAKCmBgYHtyLCBHQklGIFJ1biwgY2FjaGU9VFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSAnaGlkZSd9CiMjI0dCSUYgUnVuIyMjCiNSdW4gZnVuY3Rpb24gdGhhdCBkb2VzIEdCSUYgYW5hbHlzaXMgKHRoaXMgdGFrZXMgYSBsb25nIHRpbWU7IHJlY29tbWVuZCBydW5uaW5nIHdpdGggam9iOjpqb2IoKSB3aGVuIHdvcmtpbmcgaW4gY2h1bmtzKQoKZGlzdHJpYnV0aW9uID0gZGlzdHJpYnV0aW9uX2NoZWNrKGMoLTEyMi41MCwgMzcuNDksIC0xMjIuNDksIDM3LjUwKSwgQ0Nfc2hhcGVfc3AsIHNwZWNpZXNfc3RhbmRhcmRpemVkLCA1LCBGQUxTRSkKYGBgCgpgYGB7ciwgR0JJRiBTdW1tYXJ5LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLmtlZXA9J2FsbCd9CiMjI0dCSUYgU3VtbWFyeSMjIwojT3JnYW5pemUgdGhlIEdCSUYgYW5hbHlzaXMgb3V0cHV0CgpkID0gZGlzdHJpYnV0aW9uClBQID0gZFtbMV1dJGNvbmZpcm1lZApDQyA9IGRbWzJdXSRjb25maXJtZWQKcmFuZ2UgPSBkW1szXV0kY29uZmlybWVkCm5vX2RhdGEgPSBkW1szXV0kbm9fZGF0YSAKCmRmX1BQID0gYygpCmRmX0NDID0gYygpCmRmX3JhbmdlID0gYygpCmRmX25vX2RhdGEgPSBjKCkKZGZfbm90X2luX0dCSUYgPSBjKCkKCgpmb3IgKHMgaW4gc3BlY2llc19ib3RoJHNwZWNpZXMpIHsKICBpZihpcy5uYShzKSkgewogICAgZGZfbm90X2luX0dCSUYgPSBhcHBlbmQoZGZfbm90X2luX0dCSUYsIFRSVUUpCiAgICBkZl9QUCA9IGFwcGVuZChkZl9QUCwgTkEpCiAgICBkZl9DQyA9IGFwcGVuZChkZl9DQywgTkEpCiAgICBkZl9yYW5nZSA9IGFwcGVuZChkZl9yYW5nZSwgTkEpCiAgICBkZl9ub19kYXRhID0gYXBwZW5kKGRmX25vX2RhdGEsIE5BKQogICAgbmV4dAogIH0gZWxzZSB7CiAgICBkZl9ub3RfaW5fR0JJRiA9IGFwcGVuZChkZl9ub3RfaW5fR0JJRiwgRkFMU0UpCiAgfQogIAogIGlmKHMgJWluJSBQUCkgewogICAgZGZfUFAgPSBhcHBlbmQoZGZfUFAsIFRSVUUpCiAgfSBlbHNlIHsKICAgIGRmX1BQID0gYXBwZW5kKGRmX1BQLCBGQUxTRSkKICB9CiAgIAogIGlmKHMgJWluJSBDQykgewogICAgZGZfQ0MgPSBhcHBlbmQoZGZfQ0MsIFRSVUUpCiAgfSBlbHNlIHsKICAgIGRmX0NDID0gYXBwZW5kKGRmX0NDLCBGQUxTRSkKICB9CiAgCiAgaWYocyAlaW4lIHJhbmdlKSB7CiAgICBkZl9yYW5nZSA9IGFwcGVuZChkZl9yYW5nZSwgVFJVRSkKICB9IGVsc2UgewogICAgZGZfcmFuZ2UgPSBhcHBlbmQoZGZfcmFuZ2UsIEZBTFNFKQogIH0KICAKICBpZihzICVpbiUgbm9fZGF0YSkgewogICAgZGZfbm9fZGF0YSA9IGFwcGVuZChkZl9ub19kYXRhLCBUUlVFKQogIH0gZWxzZSB7CiAgICBkZl9ub19kYXRhID0gYXBwZW5kKGRmX25vX2RhdGEsIEZBTFNFKQogIH0KICAKfQoKR0JJRl9zdW1tYXJ5ID0gZGF0YS5mcmFtZShTcGVjaWVzID0gc3BlY2llc19ib3RoJHZlcmJhdGltX25hbWUsIAogICAgICAgICAgICAgICAgICAgICBHQklGU3BlY2llcyA9IHNwZWNpZXNfYm90aCRzcGVjaWVzLCAKICAgICAgICAgICAgICAgICAgICAgUGlsbGFyUG9pbnRPY2N1cnJlbmNlID0gZGZfUFAsIAogICAgICAgICAgICAgICAgICAgICBDQ1NPY2N1cnJlbmNlID0gZGZfQ0MsIAogICAgICAgICAgICAgICAgICAgICBSYW5nZSA9IGRmX3JhbmdlLCAKICAgICAgICAgICAgICAgICAgICAgTm9EYXRhID0gZGZfbm9fZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgIE5vdEluR0JJRiA9IGRmX25vdF9pbl9HQklGKQoKcGVyY2VudGFnZXMgPSBHQklGX3N1bW1hcnkgJT4lIAogIGdyb3VwX2J5KGFjcm9zcyhQaWxsYXJQb2ludE9jY3VycmVuY2U6Tm90SW5HQklGKSkgJT4lIAogIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHBlciA9IGNvdW50L3N1bShjb3VudCkpCgprbm93bl9zdW1tYXJ5ID0gYXMubnVtZXJpYyhHQklGX3N1bW1hcnkgJT4lIGZpbHRlcighaXMubmEoR0JJRlNwZWNpZXMpKSAlPiUgc3VtbWFyaXNlKGNvdW50ID0gc3VtKFJhbmdlID09IFRSVUUgJiBDQ1NPY2N1cnJlbmNlID09IFRSVUUpKSkKCmBgYAoKRm9jdXNlZCBvbiBqdXN0IHRoZSBgciBzYW1wbGVzYCAoYHNhbXBsZXNgKSBzYW1wbGVzLCB3ZSByZW1vdmVkIHNpbmdsZXRvbnMgYW5kIGFsbCBgciBvdmVybGFwYCAoYG92ZXJsYXBgKSBBU1ZzIHRoYXQgb3ZlcmxhcHBlZCB3aXRoIG5lZ2F0aXZlIGNvbnRyb2xzIChTdXBwbGVtZW50YWwgSW5mb3JtYXRpb24gWCksIGFuZCB3ZSByYXJlZmllZCBzYW1wbGVzIHRvIHRoZSBtaW5pbXVtIG51bWJlciBvZiByZWFkcyBvZiBhbnkgc2FtcGxlLCBsZWF2aW5nIGByIHByb2Nlc3NlZF9BU1ZzYCAoYHByb2Nlc3NlZF9BU1ZzYCkgQVNWcyBhbmQgYHIgcHJvY2Vzc2VkX3JlYWRzYCAoYHByb2Nlc3NlZF9yZWFkc2ApIHJlYWRzLiBgciBzcHJpbnRmKCIlMC4xZiUlIiwgdW5hc3NpZ25lZF9BU1ZzW3VuYXNzaWduZWRfQVNWcyRLaW5nZG9tID09ICIiLF0kZnJlcSAqIDEwMClgIChgc3ByaW50ZigiJTAuMWYlJSIsIHVuYXNzaWduZWRfQVNWc1t1bmFzc2lnbmVkX0FTVnMkS2luZ2RvbSA9PSAiIixdJGZyZXEgKiAxMDApYCkgb2YgQVNWcyB3ZXJlIHVuYXNzaWduZWQsIGFuZCB0aGUgcmVtYWluZGVyIGluY2x1ZGVkIHJlcHJlc2VudGF0aXZlcyBmcm9tIGByIHVuaXF1ZVsiUGh5bHVtIl1gIChgdW5pcXVlWyJQaHlsdW0iXWApIHBoeWxhLCBgciB1bmlxdWVbIkNsYXNzIl1gIChgdW5pcXVlWyJDbGFzcyJdYCkgY2xhc3NlcywgYHIgdW5pcXVlWyJPcmRlciJdYCAoYHVuaXF1ZVsiT3JkZXIiXWApIG9yZGVycywgYHIgdW5pcXVlWyJGYW1pbHkiXWAgKGB1bmlxdWVbIkZhbWlseSJdYCkgZmFtaWxpZXMsIGByIHVuaXF1ZVsiR2VudXMiXWAgKGB1bmlxdWVbIkdlbnVzIl1gKSBnZW5lcmEsIGFuZCBgciB1bmlxdWVbIlNwZWNpZXMiXWAgKGB1bmlxdWVbIlNwZWNpZXMiXWApIHNwZWNpZXMgKEZpZ3VyZSA0KS4gQSBicmVha2Rvd24gb2YgdGhlIHJlbGF0aXZlIHByb3BvcnRpb25zIG9mIHJlYWRzIGFuZCBBU1ZzIGFzc2lnbmVkIHRvIGVhY2ggcGh5bGEgY2FuIGJlIGZvdW5kIGluIFRhYmxlIDEuIFRvIGVuc3VyZSB0aGUgYWNjdXJhY3kgb2YgdGhlc2UgdGF4b25vbWljIGlkZW50aWZpY2F0aW9ucywgd2UgY29uZmlybWVkIHRoYXQgYHIga25vd25fc3VtbWFyeWAgKGBrbm93bl9zdW1tYXJ5YCkgb2YgYHIgdW5pcXVlWyJTcGVjaWVzIl1gIChgdW5pcXVlWyJTcGVjaWVzIl1gKSBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBrbm93bl9zdW1tYXJ5L3VuaXF1ZVsiU3BlY2llcyJdICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCBrbm93bl9zdW1tYXJ5L3VuaXF1ZVsiU3BlY2llcyJdICogMTAwKWApIGhhdmUgb2NjdXJyZW5jZSByZWNvcmRzIGluIHRoZSBDYWxpZm9ybmlhIEN1cnJlbnQgU3lzdGVtIChDQ1MpIGFuZCBrbm93biByYW5nZXMgdGhhdCBlbmNvbXBhc3MgUGlsbGFyIFBvaW50LiAoYWRkaXRpb25hbCBkZXRhaWxzIGluIFNJIDEgYW5kIFRhYmxlIFMyKS4KCmBgYHtyLCBUYWJsZSAxfQojIyNUQUJMRSAxIyMjCiNDcmVhdGUgdGFibGUgd2l0aCBzdW1tYXJ5IG9mIHJlYWRzLCBBU1ZzLCBhbmQgc3BlY2llcyBieSBwaHlsYQoKI1JlbW92ZSBhbGwgdW5jbGFzc2lmaWVkIEFTVnMgYW5kIGNvbmRlbnNlIHRvIHBoeWx1bSBsZXZlbApwaHlzZXFfdG90YWxyZWFkcyA9IHRheF9nbG9tKHBoeXNlcV9zdW1tZWQsIHRheHJhbms9IlBoeWx1bSIsIE5Bcm09VFJVRSkKUGh5bGFfUmVhZHMgPSBkYXRhLmZyYW1lKFBoeWxhID0gdGF4X3RhYmxlKHBoeXNlcV90b3RhbHJlYWRzKVssMl0sIAogICAgICAgICAgICAgICAgICAgICAgICAgUmVhZHMgPSByb3dTdW1zKG90dV90YWJsZShwaHlzZXFfdG90YWxyZWFkcykpKQogIAogIHBoeXNlcV90b3RhbEFTVnMgPSBwaHlzZXFfc3VtbWVkCiAgCiAgb3R1X3RhYmxlKHBoeXNlcV90b3RhbEFTVnMpW290dV90YWJsZShwaHlzZXFfdG90YWxBU1ZzKT4wXSA8LSAxCiAgcGh5c2VxX3RvdGFsQVNWcyA9IHRheF9nbG9tKHBoeXNlcV90b3RhbEFTVnMsIHRheHJhbms9IlBoeWx1bSIsIE5Bcm09VFJVRSkKICAKICAKICBQaHlsYV9BU1ZzID0gZGF0YS5mcmFtZShQaHlsYSA9IHRheF90YWJsZShwaHlzZXFfdG90YWxBU1ZzKVssMl0sIEFTVnMgPSByb3dTdW1zKG90dV90YWJsZShwaHlzZXFfdG90YWxBU1ZzKSkpCiAgCiAgCiAgcGh5c2VxX3NwZWNpZXNieXBoeWxhID0gcGh5c2VxX3N1bW1lZAogIHBoeXNlcV9zcGVjaWVzYnl0YXhhID0gdGF4X2dsb20ocGh5c2VxX3N1bW1lZCwgdGF4cmFuaz0iU3BlY2llcyIsIE5Bcm09VFJVRSkKICBvdHVfdGFibGUocGh5c2VxX3NwZWNpZXNieXRheGEpW290dV90YWJsZShwaHlzZXFfc3BlY2llc2J5dGF4YSk+MF0gPC0gMQogIHBoeXNlcV9zcGVjaWVzYnl0YXhhID0gdGF4X2dsb20ocGh5c2VxX3NwZWNpZXNieXRheGEsIHRheHJhbms9IlBoeWx1bSIsIE5Bcm09VFJVRSkKICAKICBQaHlsYV9TcGVjaWVzID0gIGRhdGEuZnJhbWUoUGh5bGEgPSB0YXhfdGFibGUocGh5c2VxX3NwZWNpZXNieXRheGEpWywyXSwgU3BlY2llcyA9IHJvd1N1bXMob3R1X3RhYmxlKHBoeXNlcV9zcGVjaWVzYnl0YXhhKSkpCgogIAogIGxpc3QgPSBsaXN0KFBoeWxhX1JlYWRzLCBQaHlsYV9BU1ZzLCBQaHlsYV9TcGVjaWVzKQogIGZ1bGwgPSBsaXN0ICU+JSByZWR1Y2UoZnVsbF9qb2luLCBieT0nUGh5bHVtJykKICBmdWxsW2lzLm5hKGZ1bGwpXSA8LSAwCiAgCgogIGZ1bGxfc29ydGVkID0gZnVsbFtvcmRlcigtZnVsbCRSZWFkcyksXQogIAogIGZ1bGxfc29ydGVkID0gZnVsbF9zb3J0ZWQgJT4lIAogICAgbXV0YXRlKFJlYWRzX1BlcmNlbnQgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKShSZWFkcy9zdW0oUmVhZHMpKSkgJT4lCiAgICBtdXRhdGUoQVNWc19QZXJjZW50ID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkoQVNWcy9zdW0oQVNWcykpKSAlPiUKICAgIG11dGF0ZShTcGVjaWVzX1BlcmNlbnQgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKShTcGVjaWVzL3N1bShTcGVjaWVzKSkpCiAgCiAgZnVsbF9zb3J0ZWQkUGh5bHVtID0gcmVtb3ZlX05DQkludW1zKGZ1bGxfc29ydGVkJFBoeWx1bSkKICBmdWxsX3NvcnRlZCRQaHlsdW0gPSBzdHJfcmVwbGFjZShmdWxsX3NvcnRlZCRQaHlsdW0sICJwaHlsdW1fIiwgIkNsYXNzOiAiKQogIAogIGNvbF9vcmRlciA9IGMoIlBoeWx1bSIsICJSZWFkcyIsICJSZWFkc19QZXJjZW50IiwgIkFTVnMiLCAiQVNWc19QZXJjZW50IiwgIlNwZWNpZXMiLCAiU3BlY2llc19QZXJjZW50IikKICAKICBmdWxsX3NvcnRlZCA9IGZ1bGxfc29ydGVkWyxjb2xfb3JkZXJdCiAgCgogIHdyaXRlLmNzdihmdWxsX3NvcnRlZCwgIkFuYWx5c2lzIFByb2R1Y3RzL1RhYmxlMS5jc3YiLCByb3cubmFtZXM9RkFMU0UpCiAgCiAgZnVsbF9zb3J0ZWQKYGBgCgpgYGB7ciBGaWd1cmUgNCAtLSBQaHlsb2dlbmV0aWMgVHJlZSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgZXJyb3IgPSBGQUxTRX0KIyMjRmlndXJlIDQjIyMKI0NyZWF0ZSBwaHlsb2dlbmV0aWMgdHJlZSBmb3IgYWxsIHRheG9ub21pYyBhc3NpZ25tZW50cwoKb3B0aW9ucyhnZXRDbGFzcy5tc2c9RkFMU0UpCgojQWdncmVnYXRlIHRvIHNwZWNpZXMgYXNzaWdubWVudCBhbmQgcmVtb3ZlIHRoZSBOQ0JJIGlkZW50aWZpZXJzCnB0X3BoeXNlcSA9IHRheF9nbG9tKGRhdGFfcGh5c2VxLCB0YXhyYW5rPSJTcGVjaWVzIiwgTkFybT1GQUxTRSkKdGF4X3RhYmxlKHB0X3BoeXNlcSkgPSB0YXhfdGFibGUocHRfcGh5c2VxKVshdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCJLaW5nZG9tIl09PSIiXQoKCnRheF90YWJsZShwdF9waHlzZXEpW3RheF90YWJsZShwdF9waHlzZXEpPT0iIl0gPSBOQQp0YXhfdGFibGUocHRfcGh5c2VxKSA9IHRheF90YWJsZShwdF9waHlzZXEpWyFpcy5uYSh0YXhfdGFibGUocHRfcGh5c2VxKVssIlBoeWx1bSJdKV0KbnVtYmVycyA9IHN1YigiLipfIiwiIiwgdGF4X3RhYmxlKHB0X3BoeXNlcSkpCgp0YXhhID0gYXBwbHkobnVtYmVycywgMSwgZnVuY3Rpb24oeCkgdGFpbChuYS5vbWl0KHgpLCAxKSkKCnRheF90YWJsZShwdF9waHlzZXEpID0gcmVtb3ZlX05DQkludW1zKHRheF90YWJsZShwdF9waHlzZXEpKQoKCnRheGFfY2xhc3NpZmljYXRpb24gPSBjbGFzc2lmaWNhdGlvbih0YXhhLCBkYiA9ICJuY2JpIikKCgp0YXhhX3RyZWUgPSBjbGFzczJ0cmVlKHRheGFfY2xhc3NpZmljYXRpb24sIGNoZWNrID0gVFJVRSkKCiNDaGFuZ2UgdGhlIHRpcCBsYWJlbHMgdG8gbWF0Y2ggcGh5bG9zZXEgb2JqZWN0cyAoY29kZSBvbmx5IHdvcmtzIGlmIG9yZGVyIGlzIHRoZSBzYW1lKQp0YXhhX3RyZWUkcGh5bG8kdGlwLmxhYmVsID0gcm93Lm5hbWVzKHRheF90YWJsZShwdF9waHlzZXEpKQoKCnBoeWxhID0gdW5pcXVlKHRheF90YWJsZShwdF9waHlzZXEpWywiUGh5bHVtIl0pCgpwaHlsYV9ub2RlcyA9IGMoKQpwaHlsYV9ub2RlcyA9IGRhdGEuZnJhbWUoIm5vZGVfcGh5bHVtIiA9IGMoKSwgIm5vZGUiID0gYygpKSAgCnBoeWxhX25vZGVzX3NlY29uZGFyeSA9IGRhdGEuZnJhbWUoIm5vZGVfcGh5bHVtIiA9IGMoKSwgInRpcHMiID0gYygpKSAKCmZvciAoeCBpbiBwaHlsYSkgewogIE9UVXMgPSBuYS5vbWl0KHJvdy5uYW1lcyh0YXhfdGFibGUocHRfcGh5c2VxKSlbdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCJQaHlsdW0iXSA9PSB4XSkKICBPVFVzID0gYXMudmVjdG9yKE9UVXMpCiAgbnVtID0gYXBlOjpnZXRNUkNBKHRheGFfdHJlZSRwaHlsbywgdGlwID0gT1RVcykKICBpZiAoaXMubnVsbChudW0pKSB7CiAgICBub2RlcyA9IGFzX3RpYmJsZSh0YXhhX3RyZWUkcGh5bG8pCiAgICBudW0gPSBub2RlcyRub2RlW25vZGVzJGxhYmVsID09IE9UVXNdCiAgfSAKICBkZiA9IGRhdGEuZnJhbWUoIm5vZGVfcGh5bHVtIiA9IGMoeCksICJub2RlIiA9IGMobnVtKSkKICBwaHlsYV9ub2RlcyA9IHJiaW5kKHBoeWxhX25vZGVzLCBkZikKICAKICBpZiAobGVuZ3RoKE9UVXMpIDw2KSB7CiAgICBmb3IgKHkgaW4gT1RVcykgewogICAgICBkZjIgPSBkYXRhLmZyYW1lKCJub2RlX3BoeWx1bSIgPSBjKHgpLCAidGlwcyIgPSBjKHkpKQogICAgICBwaHlsYV9ub2Rlc19zZWNvbmRhcnkgPSByYmluZChwaHlsYV9ub2Rlc19zZWNvbmRhcnksIGRmMikKICAgIH0KICB9Cn0KCnB0X3BoeXNlcSA9IG1lcmdlX3BoeWxvc2VxKHB0X3BoeXNlcSwgdGF4YV90cmVlJHBoeWxvKQoKI1VzZSBQb2x5Y2hyb21lIHBhY2thZ2UgdG8gY3JlYXRlIGEgZ29vZCBjb2xvciBwYWxldHRlIGZvciB0aGUgbnVtYmVyIG9mIHBoeWxhCnNldC5zZWVkKDU2NzYyOSkKY29sb3JzID0gY3JlYXRlUGFsZXR0ZSgyOCwgYygiI0ZGRkZGRiIpLCByYW5nZSA9IGMoMzAsIDgwKSwgdGFyZ2V0ID0gYygibm9ybWFsIiwgInByb3Rhbm9wZSIsICJkZXV0ZXJhbm9wZSIsICJ0cml0YW5vcGUiKSkKCiNDaGVjayB3aGV0aGVyIHRoZSBnaXZlbiBvcmRlciBvZiBjb2xvcnMgaGFzIGdvb2QgY29udHJhc3QgZm9yIGRpZmZlcmVudCBmb3JtcyBvZiBjb2xvcmJsaW5kbmVzcwpwYWwuc2FmZShjb2xvcnMpCgojTWFudWFsbHkgcmUtb3JkZXIgdGhlIGNvbG9ycyB0byBlbnN1cmUgdGhlcmUgaXMgZ29vZCBjb250cmFzdCBiZXR3ZWVuIGFkamFjZW50IGNvbG9ycwpjb2xvcnNfb3JkZXJlZCA9IGNvbG9yc1tjKCdOQzInLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzExJywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMyNycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMjUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzgnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzI0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkM5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMxMCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMTInLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzEzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMxJywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMxNCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMTUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzE2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkM3JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMxNycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMTgnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzE5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMyMCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMjEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMyMicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ05DMjMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdOQzI2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkM2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAnTkMyOCcpXQoKI0NvbmZpcm0gdGhhdCB0aGUgbmV3IG9yZGVyIHdvcmtzIHdlbGwKcGFsLnNhZmUoY29sb3JzX29yZGVyZWQpCgojQ3JlYXRlIGdndHJlZQpwIDwtIGdndHJlZTo6Z2d0cmVlKHB0X3BoeXNlcSwgIGxheW91dCA9ICJjaXJjdWxhciIpIAoKb3JkZXJlZF9uYW1lcyA9IGdndHJlZTo6Z2V0X3RheGFfbmFtZShwKQpvcmRlcmVkX25hbWVzID0gdW5pcXVlKG9yZGVyZWRfbmFtZXMpCm9yZGVyZWRfbmFtZXNbbWF0Y2gocm93bmFtZXModGF4X3RhYmxlKHB0X3BoeXNlcSkpLCBvcmRlcmVkX25hbWVzKV0gPSB0YXhfdGFibGUocHRfcGh5c2VxKVssIlBoeWx1bSJdCm9yZGVyZWRfbmFtZXMgPSB1bmlxdWUob3JkZXJlZF9uYW1lcykKCm5hbWVzKGNvbG9yc19vcmRlcmVkKSA9IG9yZGVyZWRfbmFtZXMKCnAgPSBwICsgZ2VvbV9mcnVpdChnZW9tID0gZ2VvbV90aWxlLCBtYXBwaW5nID0gYWVzKGZpbGwgPSBQaHlsdW0pLCB3aWR0aCA9IDMsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JzX29yZGVyZWQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JzX29yZGVyZWQpCgpwID0gcCArICBnZW9tX2ZydWl0KGRhdGE9cGh5bGFfbm9kZXNfc2Vjb25kYXJ5LCBnZW9tID0gZ2VvbV90aWxlLCBtYXBwaW5nID0gYWVzKHkgPSB0aXBzLCBmaWxsID0gbm9kZV9waHlsdW0pLCB3aWR0aCA9IDYsIHNob3cubGVnZW5kID0gRkFMU0UpICAKcCA9IHAgKyBnZ3RyZWU6Omdlb21faGlsaWdodChkYXRhPXBoeWxhX25vZGVzLCBtYXBwaW5nPWFlcyhub2RlID0gbm9kZSwgZmlsbCA9IG5vZGVfcGh5bHVtKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkKCnAgPSBwICsgZ2d0cmVlOjpnZW9tX2NsYWRlbGFiKGRhdGE9cGh5bGFfbm9kZXMsIG1hcHBpbmc9YWVzKG5vZGU9bm9kZSwgbGFiZWw9IG5vZGVfcGh5bHVtKSwgZ2VvbSA9ICJ0ZXh0IiwgYW5nbGUgPSAiYXV0byIsIG9mZnNldCA9IDUsIGZvbnRzaXplPTIsIGJhcmNvbG9yPU5BLCBzaG93LmxlZ2VuZCA9IEZBTFNFKQoKcCA9IHAgKwogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd0cmFuc3BhcmVudCcpLAogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JywgY29sb3I9TkEpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd0cmFuc3BhcmVudCcpLAogICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JykKICApCgpwYXRoID0gIkZpZ3VyZXMvRmlndXJlNC4iCnNhdmVfcGRmX3BuZyhwbG90ID0gcCwgcGF0aCA9IHBhdGgsIHcgPSAxNjksIGggPSAxNjksIHUgPSAibW0iLCBiZyA9ICJ0cmFuc3BhcmVudCIsIGRwaSA9IDYwMCkKCmBgYAoKPGNlbnRlcj4KCiFbKkZpZ3VyZSA0OiA6IFBoeWxvZ2VuZXRpYyB0cmVlIGNvbG9yZWQgYnkgdGhlIHBoeWxhIGlkZW50aWZpZWQgYWNyb3NzIGFsbCBlRE5BIHNhbXBsZXMuIEl0YWxpY2l6ZWQgdGF4b25vbWljIG5hbWVzIGFyZSB0aG9zZSB3aXRoIG5vIHBoeWx1bS1sZXZlbCBhc3NpZ25tZW50LCBzbyBjbGFzcy1sZXZlbCBhc3NpZ25tZW50cyBhcmUgdXNlZCB0byBkaWZmZXJlbnRpYXRlIChhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFkZGVkIGFmdGVyIFIgZmlndXJlIHByb2R1Y3Rpb24pKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCiMjIyMgMy4yIEluZGl2aWR1YWwtTGV2ZWwgRGlmZmVyZW5jZXMgQmV0d2VlbiBMb2NhdGlvbnMKCmBgYHtyIEV1bGVyIERpYWdyYW1zfQojIyNFdWxlciBEaWFncmFtcyMjIwoKZXVsZXJyX29wdGlvbnMocXVhbnRpdGllcyA9IGxpc3QoZm9udHNpemUgPSAxMCksIGxlZ2VuZCA9IGxpc3QoZm9udHNpemUgPSAxNCkpCgojU3Vic2V0IGFtcHZpczIgZGF0YSBieSBsb2NhdGlvbgoKYW1wX1MxID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGRhdGFfYW1wLCBMb2NhdGlvbiAlaW4lIGMoIlMxIikpCmFtcF9TMiA9IGFtcF9maWx0ZXJfc2FtcGxlcyhkYXRhX2FtcCwgTG9jYXRpb24gJWluJSBjKCJTMiIpKQphbXBfTiA9IGFtcF9maWx0ZXJfc2FtcGxlcyhkYXRhX2FtcCwgTG9jYXRpb24gJWluJSBjKCJOIikpCgojTGlzdCB0aGUgdW5pcXVlIHRheGEgYXQgZWFjaCBsb2NhdGlvbgoKUzFfdGF4YSA9IHVuaXF1ZShhbXBfUzEkdGF4JFNwZWNpZXMpClMxX3RheGEgPSBTMV90YXhhW1MxX3RheGEgIT0gIiJdClMyX3RheGEgPSB1bmlxdWUoYW1wX1MyJHRheCRTcGVjaWVzKQpTMl90YXhhID0gUzJfdGF4YVtTMl90YXhhICE9ICIiXQpOX3RheGEgPSB1bmlxdWUoYW1wX04kdGF4JFNwZWNpZXMpCk5fdGF4YSA9IE5fdGF4YVtOX3RheGEgIT0gIiJdCgojTGlzdCB0aGUgdW5pcXVlIEFTVnMgYXQgZWFjaCBsb2NhdG9uCgpTMV9BU1YgPSB1bmlxdWUoYW1wX1MxJHRheCRPVFUpClMyX0FTViA9IHVuaXF1ZShhbXBfUzIkdGF4JE9UVSkKTl9BU1YgPSB1bmlxdWUoYW1wX04kdGF4JE9UVSkKCgojVXNpbmcgZXVsZXJyLCBjcmVhdGUgZXVsZXIgZGlhZ3JhbXMgZm9yIHRheGEgYW5kIEFTVnMKCmFkZF9xdWFudGl0eV9saW5lX2JyZWFrID0gZnVuY3Rpb24odikgewogIHRhZ3MgPC0gdiRjaGlsZHJlbiRjYW52YXMuZ3JvYiRjaGlsZHJlbiRkaWFncmFtLmdyb2IuMSRjaGlsZHJlbiR0YWdzJGNoaWxkcmVuCiAgCiAgdGFncyA8LSBkby5jYWxsKGdyaWQ6OmdMaXN0LCBsYXBwbHkodGFncywgZnVuY3Rpb24oeCkgewogICAgeCRjaGlsZHJlbltbMl1dJGxhYmVsIDwtIHN1YigiIFxcJSkiLCAiJSkiLCB4JGNoaWxkcmVuW1syXV0kbGFiZWwpCiAgICBiZWZvcmUgPSBnc3ViKCAiIC4qJCIsICIiLCB4JGNoaWxkcmVuW1syXV0kbGFiZWwpCiAgICBhZnRlciA9IGdzdWIoIi4qXFwoIiwgIigiLCB4JGNoaWxkcmVuW1syXV0kbGFiZWwpCiAgICBmdWxsID0gYnF1b3RlKGF0b3AoTkEsIGF0b3AoYXRvcCh0ZXh0c3R5bGUoLihiZWZvcmUpKSwgdGV4dHN0eWxlKGl0YWxpYyguKGFmdGVyKSkpKSwgTkEpKSkKICAKICAgCiAgICB4JGNoaWxkcmVuW1syXV0kbGFiZWwgPC0gZnVsbAogICAgeCRjaGlsZHJlbltbMl1dJGp1c3QgPC0gTlVMTAogICAgeH0pKQogIAogIHYkY2hpbGRyZW4kY2FudmFzLmdyb2IkY2hpbGRyZW4kZGlhZ3JhbS5ncm9iLjEkY2hpbGRyZW4kdGFncyA8LSB0YWdzCiAgCiAgcmV0dXJuKHYpCn0KCkVfdGF4YSA8LSBldWxlcihsaXN0KFMxID0gUzFfdGF4YSwgUzIgPSBTMl90YXhhLCBOID0gTl90YXhhKSwgc2hhcGUgPSAiZWxsaXBzZSIpCkVfdGF4YV9wbG90ID0gcGxvdChFX3RheGEsIHF1YW50aXRpZXMgPSBsaXN0KHR5cGUgPSBjKCJjb3VudHMiLCAicGVyY2VudCIpLCBjZXg9MSksIGxlZ2VuZCA9IGxpc3Qoc2lkZSA9InJpZ2h0IiwgbnJvdyA9IDEsIG5jb2wgPSAzLCBjZXggPSAxKSkKRV90YXhhX3Bsb3QgPSBhZGRfcXVhbnRpdHlfbGluZV9icmVhayhFX3RheGFfcGxvdCkKCnVuaXF1ZV90YXhhX2xvY2F0aW9uIDwtIChFX3RheGEkb3JpZ2luYWwudmFsdWVzWyJTMSJdICsgCiAgICAgICAgICAgICAgICAgICBFX3RheGEkb3JpZ2luYWwudmFsdWVzWyJTMiJdICsgCiAgICAgICAgICAgICAgICAgICBFX3RheGEkb3JpZ2luYWwudmFsdWVzWyJOIl0pL3N1bShFX3RheGEkb3JpZ2luYWwudmFsdWVzKQoKCkVfQVNWIDwtIGV1bGVyKGxpc3QoUzEgPSBTMV9BU1YsIFMyID0gUzJfQVNWLCBOID0gTl9BU1YpLCBzaGFwZT0iZWxsaXBzZSIpCkVfQVNWX3Bsb3QgPSBwbG90KEVfQVNWLCBxdWFudGl0aWVzID0gbGlzdCh0eXBlID0gYygiY291bnRzIiwgInBlcmNlbnQiKSwgY2V4PTEpLCBsZWdlbmQgPSBsaXN0KHNpZGUgPSJyaWdodCIsIG5yb3cgPSAxLCBuY29sID0gMywgY2V4ID0gMSkpCkVfQVNWX3Bsb3QgPSBhZGRfcXVhbnRpdHlfbGluZV9icmVhayhFX0FTVl9wbG90KQoKdW5pcXVlX0FTVl9sb2NhdGlvbiA8LSAoRV9BU1Ykb3JpZ2luYWwudmFsdWVzWyJTMSJdICsgCiAgICAgICAgICAgICAgICAgICBFX0FTViRvcmlnaW5hbC52YWx1ZXNbIlMyIl0gKyAKICAgICAgICAgICAgICAgICAgIEVfQVNWJG9yaWdpbmFsLnZhbHVlc1siTiJdKS9zdW0oRV9BU1Ykb3JpZ2luYWwudmFsdWVzKQoKCgpgYGAKCkFjcm9zcyBib3RoIHRheGEgKG49YGBgIHIgdW5pcXVlWyJTcGVjaWVzIl1gYHVuaXF1ZVsiU3BlY2llcyJdIGBgYCkgYW5kIEFTVnMgKG49YHIgcHJvY2Vzc2VkX0FTVnNgIGBwcm9jZXNzZWRfQVNWc2ApLCBhbGwgdGhyZWUgbG9jYXRpb25zIGhhZCB1bmlxdWUgZWxlbWVudHMsIHN1Z2dlc3RpbmcgdGhhdCB0aGVyZSB3YXMgbm90IGNvbXBsZXRlIG1peGluZyBvZiBlRE5BIGFjcm9zcyBtaWNyby1oYWJpdGF0cy4gYHIgc3ByaW50ZigiJTAuMWYlJSIsIHVuaXF1ZV90YXhhX2xvY2F0aW9uICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCB1bmlxdWVfdGF4YV9sb2NhdGlvbiAqIDEwMClgIG9mIHRheGEgYW5kIGByIHNwcmludGYoIiUwLjFmJSUiLCB1bmlxdWVfQVNWX2xvY2F0aW9uICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCB1bmlxdWVfQVNWX2xvY2F0aW9uICogMTAwKWAgb2YgQVNWcyB3ZXJlIHVuaXF1ZSB0byBvbmUgb2YgdGhlIHRocmVlIGxvY2F0aW9ucyAoRmlndXJlIDUpLiBBdCBib3RoIHRoZSB0YXhhIGFuZCBBU1YgbGV2ZWwsIFMxIGhhZCBtb3JlIHVuaXF1ZSBlbGVtZW50cyB0aGFuIFMyIGFuZCBuZWFyc2hvcmUsIGFsdGhvdWdoIHRoaXMgZWZmZWN0IHdhcyBtb3JlIHByb25vdW5jZWQgYWNyb3NzIEFTVnMuIEFTVnMgYW5kIHRheGEgc2hhcmVkIGFjcm9zcyBwYWlycyBvZiB0d28gbG9jYXRpb25zIHdlcmUgdGhlIGxlYXN0IGNvbW1vbiBlbGVtZW50cy4KCmBgYHtyIEZpZ3VyZSA1fQoKZXVsZXIgPSAod3JhcF9lbGVtZW50cyhwYW5lbCA9IGdyaWQ6OnRleHRHcm9iKCdBKScsIGhqdXN0ID0gNiwgdmp1c3QgPSAxLCBncD1ncGFyKGZvbnRzaXplPTE0LCBmb250ZmFjZSA9ICdib2xkJykpKSArIAogICAgICAgICAgIHdyYXBfZWxlbWVudHMgKHBhbmVsID0gZ3JpZDo6dGV4dEdyb2IoJ0IpJywgaGp1c3QgPSA2LCB2anVzdCA9IDEsIGdwPWdwYXIoZm9udHNpemU9MTQsIGZvbnRmYWNlID0gJ2JvbGQnKSkpKSAvIAogICh3cmFwX2VsZW1lbnRzKHBhbmVsID0gRV90YXhhX3Bsb3QkY2hpbGRyZW4kY2FudmFzLmdyb2IpICsgd3JhcF9lbGVtZW50cyhwYW5lbCA9IEVfQVNWX3Bsb3QkY2hpbGRyZW4kY2FudmFzLmdyb2IpKSAvIAogIHdyYXBfZWxlbWVudHMocGFuZWwgPSBFX3RheGFfcGxvdCRjaGlsZHJlbiRsZWdlbmQuZ3JvYikgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDEwLDEpKSAKCnBhdGggPSAiRmlndXJlcy9GaWd1cmU1LiIKc2F2ZV9wZGZfcG5nKHBsb3QgPSBldWxlciwgcGF0aCA9IHBhdGgsIHcgPSAxNjksIGggPSAxMTAsIHUgPSAibW0iLCBiZyA9ICJ0cmFuc3BhcmVudCIsIGRwaSA9IDYwMCkKYGBgCgo8Y2VudGVyPgoKIVsqRmlndXJlIDU6IEFyZWEtcHJvcG9ydGlvbmFsIEV1bGVyIGRpYWdyYW1zIHNob3dpbmcgdGhlIG92ZXJsYXAgaW4gdGF4YSAoQSkgYW5kIEFTVnMgKEIpIGJldHdlZW4gbG9jYXRpb25zIFMxLCBTMiwgYW5kIE4uKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCmBgYHtyIEluZGljYXRvciBTcGVjaWVzIEFuYWx5c2lzLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgojRnVuY3Rpb24gZm9yIGNyZWF0aW5nIGluZGljYXRvciBzcGVjaWVzIGhlYXRtYXAgZnJvbSBwaHlzZXEgZGF0YQoKaW5kaWNhdG9yX2hlYXRtYXAgPC0gZnVuY3Rpb24ocGh5c2VxLCBhc3YpIHsKICAKICAjSWYgYW5hbHl6aW5nIGJ5IHRheGEsIHJlbW92ZSBhbGwgdW5jbGFzc2lmaWVkIEFTVnMgYW5kIGNvbmRlbnNlIHRvIHNwZWNpZXMgYXNzaWdubWVudHMKICBpZihhc3YgPT0gRkFMU0UpIHsKICAgIHBoeXNlcSA9IHRheF9nbG9tKHBoeXNlcSwgdGF4cmFuaz0iU3BlY2llcyIsIE5Bcm09VFJVRSkKICAgIHRheF90YWJsZShwaHlzZXEpID0gcmVtb3ZlX05DQkludW1zKHRheF90YWJsZShwaHlzZXEpKQogICAgI3RheF90YWJsZShwaHlzZXEpID0gZ3N1YigiXFxfLioiLCIiLHRheF90YWJsZShwaHlzZXEpKQogIH0gZWxzZSB7CiAgICB0YXhfdGFibGUocGh5c2VxKSA9IHJlbW92ZV9OQ0JJbnVtcyh0YXhfdGFibGUocGh5c2VxKSkKICB9CiAgCiAgI0NvbnZlcnQgdG8gcHJlc2VuY2UvYWJzZW5jZSBkYXRhCiAgb3R1X3RhYmxlKHBoeXNlcSlbb3R1X3RhYmxlKHBoeXNlcSkgPjBdIDwtIDEKICAKICAjVXNlIGluZGljc3BlY2llcyBwYWNrYWdlIHRvIGdldCB0b3AgdGF4YQogIGluZHZhbCA9IG11bHRpcGF0dCh0KG90dV90YWJsZShwaHlzZXEpKSx0KHNhbXBsZV9kYXRhKHBoeXNlcSlbLCJMb2NhdGlvbiJdKSwgY29udHJvbCA9IGhvdyhucGVybT05OTkpLCBkdWxlZyA9IFRSVUUpCiAgdG9wX04gPSByb3duYW1lcyhpbmR2YWwkc2lnbiAlPiUgZmlsdGVyKHAudmFsdWUgPCAwLjA1KSAlPiUgZmlsdGVyKHMuTiA9PSAxKSAgJT4lIGZpbHRlcihzdGF0ID4gLjcpKQogIHRvcF9TMSA9IHJvd25hbWVzKGluZHZhbCRzaWduICU+JSBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSBmaWx0ZXIocy5TMSA9PSAxKSAgJT4lIGZpbHRlcihzdGF0ID4gLjcpKQogIHRvcF9TMiA9IHJvd25hbWVzKGluZHZhbCRzaWduICU+JSBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSBmaWx0ZXIocy5TMiA9PSAxKSAgJT4lIGZpbHRlcihzdGF0ID4gLjcpKQogIAogIGluZGljYXRvcnNfYWxsID0gYyh0b3BfTiwgdG9wX1MxLCB0b3BfUzIpCiAgCiAgI01lcmdlIHNhbXBsZXMgYnkgc2l0ZS90aW1lIGJlZm9yZSBwbG90dGluZyAKICBwaHlzZXFfbWVyZ2UgPSBtZXJnZV9zYW1wbGVzKHBoeXNlcSwgIlNpdGVCeVRpbWUiKQogIAogICNVcGRhdGUgbWV0YWRhdGEgYWNjb3JkaW5nbHkKICB1cGRhdGVkX21ldGFkYXRhID0gYXMubWF0cml4KHNhbXBsZV9kYXRhKHBoeXNlcSlbLCBjKCJTaXRlQnlUaW1lIiwgIlRpbWUiLCAiTG9jYXRpb24iLCAiVCIsICJTIildKQogIHVwZGF0ZWRfbWV0YWRhdGEgPSBhcy5kYXRhLmZyYW1lKHVwZGF0ZWRfbWV0YWRhdGEpCiAgdXBkYXRlZF9tZXRhZGF0YSRTaXRlQnlUaW1lID0gYXMuZmFjdG9yKHVwZGF0ZWRfbWV0YWRhdGEkU2l0ZUJ5VGltZSkKICB1cGRhdGVkX21ldGFkYXRhJFRpbWUgPSBhcy5mYWN0b3IodXBkYXRlZF9tZXRhZGF0YSRUaW1lKQogIHVwZGF0ZWRfbWV0YWRhdGEkTG9jYXRpb24gPSBhcy5mYWN0b3IodXBkYXRlZF9tZXRhZGF0YSRMb2NhdGlvbikKICB1cGRhdGVkX21ldGFkYXRhID0gZGlzdGluY3QodXBkYXRlZF9tZXRhZGF0YSkKICByb3duYW1lcyh1cGRhdGVkX21ldGFkYXRhKSA9IHVwZGF0ZWRfbWV0YWRhdGFbLCdTaXRlQnlUaW1lJ10KICBzYW1wbGVfZGF0YShwaHlzZXFfbWVyZ2UpIDwtIHNhbXBsZV9kYXRhKHVwZGF0ZWRfbWV0YWRhdGEpCgogICNEaXZpZGUgYWxsIG1lcmdlZCBzYW1wbGVzIGJ5IHRoZSBudW1iZXIgb2Ygc2FtcGxlcyB0aGV5IHJlcHJlc2VudCAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpLzMKICAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTE6MzAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxMTozMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldLzMKICAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTQ6MDAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxNDowMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldLzMKIAogICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTc6MDAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxNzowMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldLzMKICAKICAjQWRkIGxhYmVscyB0byB0aGUgaW5kaWNhdG9yIHNwZWNpZXMgZm9yIHBsb3R0aW5nCiAgaW5kaWNhdG9yc19vbmx5IDwtcHJ1bmVfdGF4YShjb2xuYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkgJWluJSBpbmRpY2F0b3JzX2FsbCwgcGh5c2VxX21lcmdlKQogIAogIGFkZF9pbmRpY2F0b3JfbGFiZWwgPC0gZnVuY3Rpb24oWCkgewogICAgaWYgKFggJWluJSB0b3BfTikgeyByZXR1cm4oIk4iKX0KICAgIGVsc2UgaWYgKFggJWluJSB0b3BfUzEpIHsgcmV0dXJuKCJTMSIpfQogICAgZWxzZSBpZiAoWCAlaW4lIHRvcF9TMikge3JldHVybiAoIlMyIil9CiAgICBlbHNlIHtyZXR1cm4oIk5BIil9CiAgfQogIAogIGluZGljYXRvcnM8LSBzYXBwbHkocm93bmFtZXModGF4X3RhYmxlKGluZGljYXRvcnNfb25seSkpLCBhZGRfaW5kaWNhdG9yX2xhYmVsKQoKICB0YXhfdGFibGUoaW5kaWNhdG9yc19vbmx5KSA9IGNiaW5kKHRheF90YWJsZShpbmRpY2F0b3JzX29ubHkpLCBpbmRpY2F0b3JzKQoKICAjUGxvdAogIHBsb3QgPSBwbG90X2hlYXRtYXAoaW5kaWNhdG9yc19vbmx5LCAKICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgZGlzdGFuY2UgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICB0YXhhLm9yZGVyID0gcmV2KGluZGljYXRvcnNfYWxsKSwgCiAgICAgICAgICAgICAgICAgICAgICB0YXhhLmxhYmVsID0gIlNwZWNpZXMiLCAKICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZS5sYWJlbCA9ICJUaW1lIiwgCiAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUub3JkZXIgPSAiVGltZSIpICsgCiAgICBmYWNldF9ncmlkKGZhY3RvcihpbmRpY2F0b3JzLCBsZXZlbHM9YygnUzEnLCAnUzInLCAnTicpKX5mYWN0b3IoTG9jYXRpb24sIGxldmVscz1jKCdTMScsICdTMicsICdOJykpLCAKICAgICAgICAgICAgICAgc2NhbGVzPSJmcmVlIiwgCiAgICAgICAgICAgICAgIHNwYWNlID0gImZyZWUiLCAKICAgICAgICAgICAgICAgc3dpdGNoID0gInkiKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJibGFjayIsIGhpZ2ggPSAiI0I1RDdFNCIpICsgCiAgICB0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDEwKSArIAogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3Q9MSkpICsKICAgIHRoZW1lKHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikgICsKICAgIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxKSkpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyhmaWxsID0gIlByb3BvcnRpb24gb2YgUG9zaXRpdmUgRGV0ZWN0cyIsIHRpdGxlID0gIkxvY2F0aW9ucyIpICsKICAgIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIGZhY2UgPSAiaXRhbGljIiksIAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIikpICsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3JiYXIoYmFyd2lkdGggPSAxMCkpCiAgCiAgcGxvdCRzY2FsZXMkc2NhbGVzW1syXV0kbmFtZSA8LSAiSW5kaWNhdG9ycyIKICAKICByZXR1cm4obGlzdChwbG90ID0gcGxvdCwgCiAgICAgICAgICAgICAgdG9wX04gPSB0b3BfTiwgCiAgICAgICAgICAgICAgdG9wX1MxID0gdG9wX1MxLCAKICAgICAgICAgICAgICB0b3BfUzIgPSB0b3BfUzIsIAogICAgICAgICAgICAgIGFsbF9pbmRpY2F0b3JzID0gaW5kaWNhdG9yc19hbGwsIAogICAgICAgICAgICAgIGZ1bGxfb3V0cHV0ID0gaW5kdmFsKSkKfQoKaGVhdG1hcF90YXhhID0gaW5kaWNhdG9yX2hlYXRtYXAoZGF0YV9waHlzZXEsIEZBTFNFKQpoZWF0bWFwX0FTViA9IGluZGljYXRvcl9oZWF0bWFwKGRhdGFfcGh5c2VxLCBUUlVFKQoKaW5kaWNhdG9yX0FTVnMgPSBkYXRhX2FtcCR0YXhbaGVhdG1hcF9BU1YkYWxsX2luZGljYXRvcnMsXQp1bmFzc2lnbmVkX2luZGljYXRvcl9BU1ZzID0gaW5kaWNhdG9yX0FTVnMgJT4lIGdyb3VwX2J5KEtpbmdkb20pICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIG11dGF0ZSAoZnJlcSA9IG4gLyBzdW0obikpCgoKaWRlbnRpZnlfbmV3X2luZGljYXRvcnMgPSBmdW5jdGlvbihkYXRhX2FtcCwgdG9wX0FTVnMsIHRvcF90YXhhKSB7CiAgdG9wX0FTVnMgPSBkYXRhX2FtcCR0YXhbdG9wX0FTVnMsXQogIHRvcF90YXhhID0gZGF0YV9hbXAkdGF4W3RvcF90YXhhLF0KICAKICB0b3BfQVNWcyA9IHRvcF9BU1ZzJFNwZWNpZXNbdG9wX0FTVnMkU3BlY2llcyAhPSAiIl0KICB0b3BfdGF4YSA9IHRvcF90YXhhJFNwZWNpZXMKICAKICB0b3BfQVNWcyA9IHJlbW92ZV9OQ0JJbnVtcyh0b3BfQVNWcykKICB0b3BfdGF4YSA9IHJlbW92ZV9OQ0JJbnVtcyh0b3BfdGF4YSkKICByZXR1cm4oc2V0ZGlmZih0b3BfQVNWcywgdG9wX3RheGEpKQp9CgpOX0FTVl9leHRyYSA9IHNvcnQoaWRlbnRpZnlfbmV3X2luZGljYXRvcnMoZGF0YV9hbXAsIGhlYXRtYXBfQVNWJHRvcF9OLCBoZWF0bWFwX3RheGEkdG9wX04pKQpTMV9BU1ZfZXh0cmEgPSBzb3J0KGlkZW50aWZ5X25ld19pbmRpY2F0b3JzKGRhdGFfYW1wLCBoZWF0bWFwX0FTViR0b3BfUzEsIGhlYXRtYXBfdGF4YSR0b3BfUzEpKQpTMl9BU1ZfZXh0cmEgPSBzb3J0KGlkZW50aWZ5X25ld19pbmRpY2F0b3JzKGRhdGFfYW1wLCBoZWF0bWFwX0FTViR0b3BfUzIsIGhlYXRtYXBfdGF4YSR0b3BfUzIpKQoKYGBgCgpgYGB7ciBGaWd1cmUgNn0KcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTYuIgpzYXZlX3BkZl9wbmcocGxvdCA9IGhlYXRtYXBfdGF4YSRwbG90LCBwYXRoID0gcGF0aCwgdyA9IDE2OSwgaCA9IDEwMCwgdSA9ICJtbSIsIGJnID0gInRyYW5zcGFyZW50IiwgZHBpID0gNjAwKQpgYGAKCjxjZW50ZXI+CgohWypGaWd1cmUgNjogSGVhdCBtYXAgb2YgaWRlbnRpZmllZCBpbmRpY2F0b3IgdGF4YSBmb3IgYWxsIHRocmVlIGxvY2F0aW9ucyBvdmVyIHRpbWUsIHNjYWxlZCBieSB0aGUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMgdGhhdCBkZXRlY3RlZCB0aGF0IHNwZWNpZXMuKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KClVzaW5nIGFuIGluZGljYXRvciBzcGVjaWVzIGZyYW1ld29yayBwcm9kdWNlZCBzaW1pbGFyIHRyZW5kcyB0byB0aGUgYW5hbHlzaXMgb2YgdW5pcXVlIHRheGEgYW5kIEFTVnM7IGFsbCB0aHJlZSBsb2NhdGlvbnMgaGFkIGluZGljYXRvciB0YXhhIGFuZCBBU1ZzLCBhbmQgUzEgaGFkIG1vcmUgaW5kaWNhdG9yIGVsZW1lbnRzIHRoYW4gb3RoZXIgbG9jYXRpb25zLiBCeSB0YXhhLCB3ZSBpZGVudGlmaWVkIGByIGxlbmd0aChoZWF0bWFwX3RheGEkYWxsX2luZGljYXRvcnMpYCBgbGVuZ3RoKGhlYXRtYXBfdGF4YSRhbGxfaW5kaWNhdG9ycylgIGluZGljYXRvciB0YXhhOiBgciBsZW5ndGgoaGVhdG1hcF90YXhhJHRvcF9TMSlgIGBsZW5ndGgoaGVhdG1hcF90YXhhJHRvcF9TMSlgIGZvciBTMSwgYHIgbGVuZ3RoKGhlYXRtYXBfdGF4YSR0b3BfUzIpYCBgbGVuZ3RoKGhlYXRtYXBfdGF4YSR0b3BfUzIpYCBmb3IgUzIsIGFuZCBgciBsZW5ndGgoaGVhdG1hcF90YXhhJHRvcF9OKWAgYGxlbmd0aChoZWF0bWFwX3RheGEkdG9wX04pYCBmb3IgbmVhcnNob3JlIChGaWd1cmUgNikuIEJ5IEFTVnMsIHdlIGZvdW5kIG1vcmUgaW5kaWNhdG9ycyBvdmVyYWxsLiBXZSBpZGVudGlmaWVkIGByIGxlbmd0aChoZWF0bWFwX0FTViRhbGxfaW5kaWNhdG9ycylgIGBsZW5ndGgoaGVhdG1hcF9BU1YkYWxsX2luZGljYXRvcnMpYCBpbmRpY2F0b3IgQVNWczogYHIgbGVuZ3RoKGhlYXRtYXBfQVNWJHRvcF9TMSlgIGBsZW5ndGgoaGVhdG1hcF9BU1YkdG9wX1MxKWAgZm9yIFMxLCBgciBsZW5ndGgoaGVhdG1hcF9BU1YkdG9wX1MyKWAgYGxlbmd0aChoZWF0bWFwX0FTViR0b3BfUzIpYCBmb3IgUzIsIGFuZCBgciBsZW5ndGgoaGVhdG1hcF9BU1YkdG9wX04pYCBgbGVuZ3RoKGhlYXRtYXBfQVNWJHRvcF9OKWAgZm9yIG5lYXJzaG9yZSAoU3VwcGxlbWVudGFsIEZpZ3VyZSBYKS4gTW9zdCAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHVuYXNzaWduZWRfaW5kaWNhdG9yX0FTVnNbdW5hc3NpZ25lZF9pbmRpY2F0b3JfQVNWcyRLaW5nZG9tID09ICIiLF0kZnJlcSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgdW5hc3NpZ25lZF9pbmRpY2F0b3JfQVNWc1t1bmFzc2lnbmVkX2luZGljYXRvcl9BU1ZzJEtpbmdkb20gPT0gIiIsXSRmcmVxICogMTAwKWApIGluZGljYXRvciBBU1ZzIGhhZCBubyB0YXhvbm9taWMgYXNzaWdubWVudCwgYnV0IHRoZSBvbmVzIHRoYXQgZGlkIGluY2x1ZGVkIHNldmVyYWwgc3BlY2llcyBiZXlvbmQgdGhlIG9yaWdpbmFsIGluZGljYXRvciB0YXhhLCBhdCBTMSAoKmByIHRvU3RyaW5nKFMxX0FTVl9leHRyYSlgKiBgdG9TdHJpbmcoUzFfQVNWX2V4dHJhKWApLCBTMiAoKmByIHRvU3RyaW5nKFMyX0FTVl9leHRyYSlgKiBgdG9TdHJpbmcoUzJfQVNWX2V4dHJhKWApLCBhbmQgbmVhcnNob3JlICgqYHIgdG9TdHJpbmcoTl9BU1ZfZXh0cmEpYCogYHRvU3RyaW5nKE5fQVNWX2V4dHJhKWApLgoKIyMjIyAzLjMuIENvbW11bml0eS1MZXZlbCBEaWZmZXJlbmNlcyBiZXR3ZWVuIExvY2F0aW9ucwoKYGBge3IgSmFjY2FyZCBEaXNzaW1pbGFyaXl9CiNDYWxjdWxhdGUgSmFjY2FyZCBkaXNzaW1pbGFyaXR5IG1hdHJpY2VzCmphY2NhcmRfZnVsbCA9IHZlZ2Rpc3QodChkYXRhX2FtcCRhYnVuZCksIGJpbmFyeSA9IFRSVUUsIG1ldGhvZCA9ICJqYWNjYXJkIikKamFjY2FyZF90YXhhID0gdmVnZGlzdCh0KGRhdGFfYW1wX3RheGEkYWJ1bmQpLCBiaW5hcnkgPSBUUlVFLCBtZXRob2QgPSAiamFjY2FyZCIpCmBgYAoKYGBge3IgUEVSTUFOT1ZBfQoKc2V0LnNlZWQoMCkKCiNQRVJNQU5PVkEgb24gZnVsbCBkYXRhIHNldApwZXJtdXRlc3QoYmV0YWRpc3BlcihqYWNjYXJkX2Z1bGwsIGRhdGFfYW1wJG1ldGFkYXRhJExvY2F0aW9uKSkKYWRvbmlzMihqYWNjYXJkX2Z1bGwgfiBMb2NhdGlvbiArIFRpbWUgKyBEZXJlcGxpY2F0ZWRfU2FtcGxlX05hbWUgLCBkYXRhID0gZGF0YV9hbXAkbWV0YWRhdGEpCgojUEVSTUFOT1ZBIG9uIHRheGEgZGF0YSBzZXQKcGVybXV0ZXN0KGJldGFkaXNwZXIoamFjY2FyZF90YXhhLCBkYXRhX2FtcF90YXhhJG1ldGFkYXRhJExvY2F0aW9uKSkKYWRvbmlzMihqYWNjYXJkX3RheGEgfiBMb2NhdGlvbiArIFRpbWUgKyBEZXJlcGxpY2F0ZWRfU2FtcGxlX05hbWUsIGRhdGEgPSBkYXRhX2FtcF90YXhhJG1ldGFkYXRhKQoKYGBgCgpgYGB7ciBOTURTIFNjcmVlLCBtZXNzYWdlPUZBTFNFLCBjYWNoZSA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQoKI0NoZWNrIHRoZSBzdHJlc3MgdnMuIGRpbWVuc2lvbiBwbG90CgojIEZ1bmN0aW9uIHRoYXQgcGVyZm9ybXMgYSBOTURTIGZvciAxLTEwIGRpbWVuc2lvbnMgYW5kIHBsb3RzIHRoZSBuciBvZiBkaW1lbnNpb25zIHZzIHRoZSBzdHJlc3MKTk1EUy5zY3JlZSA8LSBmdW5jdGlvbih4KSB7ICN3aGVyZSB4IGlzIHRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lIHZhcmlhYmxlCiAgcGxvdChyZXAoMSwgMTApLCByZXBsaWNhdGUoMTAsIG1ldGFNRFMoeCwgYXV0b3RyYW5zZm9ybSA9IEYsIGsgPSAxKSRzdHJlc3MpLCB4bGltID0gYygxLCAxMCkseWxpbSA9IGMoMCwgMC4zMCksIHhsYWIgPSAiIyBvZiBEaW1lbnNpb25zIiwgeWxhYiA9ICJTdHJlc3MiLCBtYWluID0gIk5NRFMgc3RyZXNzIHBsb3QiKQogIGZvciAoaSBpbiAxOjEwKSB7CiAgICBwb2ludHMocmVwKGkgKyAxLDEwKSxyZXBsaWNhdGUoMTAsIG1ldGFNRFMoeCwgYXV0b3RyYW5zZm9ybSA9IEYsIGsgPSBpICsgMSkkc3RyZXNzKSkKICB9Cn0KCiMgVXNlIE5NRFMuc2NyZWUgZnVuY3Rpb24gdG8gY2hvb3NlIHRoZSBvcHRpbWFsIG5yIG9mIGRpbWVuc2lvbnMKTk1EUy5zY3JlZShqYWNjYXJkX2Z1bGwpCk5NRFMuc2NyZWUoamFjY2FyZF90YXhhKQoKYGBgCgpgYGB7ciBQQU0gUHJlcGFyYXRpb24sIG1lc3NhZ2U9RkFMU0UsIGNhY2hlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiNFc3RhYmxpc2ggZnVuY3Rpb25zIGZvciBQQU0gY2x1c3RlcmluZyBhbGdvcml0aG0KClBBTV92YWxpZGF0aW9uIDwtIGZ1bmN0aW9uKGRpc3QpIHsKICAKICBrX2xpc3QgPC0gYygpCiAgYXZnX3NpbF93aWR0aCA8LSBjKDApCiAgZm9yICh4IGluIDE6KG5yb3coYXMubWF0cml4KGRpc3QpKS0xKSl7CiAgICBQQU0gPSBwYW0oZGlzdCwgaz14LCBkaXNzID0gVFJVRSkKICAgIGF2Z19zaWxfd2lkdGggPC0gYyhhdmdfc2lsX3dpZHRoLCBQQU0kc2lsaW5mbyRhdmcud2lkdGgpCiAgICBrX2xpc3QgPC0gYyhrX2xpc3QsIHgpCiAgfQogIAogIFBBTV92YWxpZGF0aW9uIDwtIGRhdGEuZnJhbWUgKGsgPSBrX2xpc3QsIHNpbF93aWR0aCA9IGF2Z19zaWxfd2lkdGgsIHhfbWF4ID0gd2hpY2gubWF4KGF2Z19zaWxfd2lkdGgpKQogIHJldHVybihQQU1fdmFsaWRhdGlvbikKfQoKUEFNX3ZhbGlkYXRpb25fdml6IDwtIGZ1bmN0aW9uKFBBTV92YWxpZGF0aW9uKSB7CiAgcGxvdCA9IGdncGxvdChkYXRhID0gUEFNX3ZhbGlkYXRpb24sIAogICAgICAgICAgICAgICAgYWVzKHg9aywgeSA9IHNpbF93aWR0aCkpICsgCiAgICBnZW9tX2xpbmUoKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICB4bGFiKCJLIikgKyAKICAgIHlsYWIoIkF2ZXJhZ2UgU2lsaG91ZXR0ZSBXaWR0aCIpICsgCiAgICBnZ3RpdGxlKCJDbHVzdGVyIFZhbGlkYXRpb24gdXNpbmcgQXZlcmFnZSBTaWxob3VldHRlIFdpZHRoIikgKyAKICAgIGdlb21fc2VnbWVudChhZXMoeD0geF9tYXhbMV0sIAogICAgICAgICAgICAgICAgICAgICB5ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgIHhlbmQgPSB4X21heFsxXSwgCiAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBzaWxfd2lkdGhbeF9tYXhbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiksIAogICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgCiAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkKICByZXR1cm4ocGxvdCkKfQoKUEFNX3NpbGhvdWV0dGVfdml6XzMgPC0gZnVuY3Rpb24oUEFNLCBzYW1wbGVfZGF0YSkgewogIAogIHNldC5zZWVkKDApCiAgUEFNX2RmID0gZGF0YS5mcmFtZShQQU0kc2lsaW5mbyR3aWR0aHMpCiAgUEFNX2RmIDwtIGNiaW5kKFBBTV9kZiwgWCA9IHJvdy5uYW1lcyhQQU1fZGYpKQogIFBBTV9kZiA8LSBtZXJnZShQQU1fZGYsIHNhbXBsZV9kYXRhLCBieSA9ICJYIikKICBQQU1fZGYkY2x1c3RlciA8LSBhcy5mYWN0b3IoUEFNX2RmJGNsdXN0ZXIpCiAgUEFNX2RmJHJhbmRvbSA9IHNhbXBsZSgxMDAwLCBzaXplID0gbnJvdyhQQU1fZGYpLCByZXBsYWNlID0gRkFMU0UpCiAgCiAgCiAgZ2dwbG90KGRhdGEgPSBQQU1fZGYsIAogICAgICAgICBhZXMoeD1zaWxfd2lkdGgsIHkgPSByZW9yZGVyKFgsIHJhbmRvbSksIGZpbGwgPSBMb2NhdGlvbikpICsgCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZT1Mb2NhdGlvbiwgY29sb3I9VGltZSksIHNpemUgPSAyLCBwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIgKGhlaWdodCA9IDIwLCB3aWR0aCA9IDApKSArIAogICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTYsIDE1LCAxNykpICsgCiAgICBmYWNldF9ncmlkKGNsdXN0ZXIgfiAuLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IikgKwogICAgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZT1UUlVFLCBiZWdpbiA9IDAsIGVuZCA9IC45NywgZGlyZWN0aW9uID0gLTEpICsgCiAgICB4bGFiKCJTaWxob3VldHRlIFdpZHRoIikgKyAKICAgIHlsYWIoIiIpICsgCiAgICBnZW9tX3ZsaW5lICh4aW50ZXJjZXB0ID0gUEFNJHNpbGluZm8kYXZnLndpZHRoLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArIAogICAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMCkgKyAKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCkpICsgCiAgICBnZ3RpdGxlKCJQQU0gQ2x1c3RlcmluZyBWaXN1YWxpemF0aW9uIikgKyAKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIHBhbmVsLmJvcmRlcj1lbGVtZW50X3JlY3QoY29sb3VyPSJibGFjayIsc2l6ZT0xLCBmaWxsID0gTkEpKSArIAogICAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBleHBhbnNpb24oYWRkID0gNDApKQp9CmBgYAoKYGBge3IgRmlndXJlIDcsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CgpOTURTX1BBTSA8LSBmdW5jdGlvbihhbXAsIGphY2NhcmQsIGRpbSwgUEFNX2xvZ2ljYWwpIHsKICBzZXQuc2VlZCgwKQogIE5NRFMgPSBtZXRhTURTKGphY2NhcmQsIGRpbSwgdHJ5bWF4ID0gMTAwLCB0aWR5ID0gVFJVRSkKICAKICBOTURTX3N0cmVzcyA9IHN0cmVzc3Bsb3QoTk1EUykKICAKICBkYXRhLnNjb3JlcyA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhOTURTKSkKICBkYXRhLnNjb3JlcyRYIDwtIHJvd25hbWVzKGRhdGEuc2NvcmVzKQogIGRhdGEuc2NvcmVzIDwtIG1lcmdlKGRhdGEuc2NvcmVzLCBhbXAkbWV0YWRhdGEpCiAgCiAgYW5ub3RhdGlvbnMxIDwtIGRhdGEuZnJhbWUoCiAgICB4cG9zID0gYyhJbmYpLCB5cG9zID0gIGMoLUluZiksIAogICAgYW5ub3RhdGVUZXh0ID0gYyhwYXN0ZSgiU3RyZXNzOiIsIHJvdW5kKE5NRFMkc3RyZXNzLCAzKSkpLAogICAgaGp1c3R2YXIgPSBjKDEpLCAgCiAgICB2anVzdHZhciA9IGMoLS41KSkKICAKICBwbG90MSA9IGdncGxvdChkYXRhPWRhdGEuc2NvcmVzLCBhZXMoeD1OTURTMSwgeT1OTURTMikpICsgCiAgICB0aGVtZV9saWdodCgpICsgCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZT1Mb2NhdGlvbiwgY29sb3I9VGltZSksIHNpemUgPSAyKSArIAogICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTYsIDE1LCAxNykpICsgCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICAgIGdndGl0bGUgKCJBKSBuTk1EUyBPcmRpbmF0aW9uIChKYWNjYXJkIERpc3NpbWlsYXJpdHkpIikgKwogICAgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZT1UUlVFLCBiZWdpbiA9IDAsIGVuZCA9IC45NywgZGlyZWN0aW9uID0gLTEpICsKICAgIHN0YXRfZWxsaXBzZShhZXMoZ3JvdXA9TG9jYXRpb24pLCB0eXBlID0gInQiLGxpbmV0eXBlID0gMiwgYWxwaGEgPSAxKSAKICAKCiAgcGxvdDEgPSBwbG90MSArIAogICAgZ2VvbV90ZXh0KGRhdGEgPSBhbm5vdGF0aW9uczEsIGFlcyh4PXhwb3MsIHk9eXBvcywgaGp1c3QgPSBoanVzdHZhciwgdmp1c3Q9dmp1c3R2YXIsIGxhYmVsID0gYW5ub3RhdGVUZXh0KSkgKyAKICAgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEwKQogIAogICBpZihQQU1fbG9naWNhbCA9PSBUUlVFKSB7CiAgdmFsaWRhdGVkX2sgPSBQQU1fdmFsaWRhdGlvbihqYWNjYXJkKQogIFBBTV92YWxpZGF0aW9uID0gUEFNX3ZhbGlkYXRpb25fdml6KHZhbGlkYXRlZF9rKQogIAogIFBBTSA9IHBhbShqYWNjYXJkLCBrPXZhbGlkYXRlZF9rJHhfbWF4WzFdLCBkaXNzID0gVFJVRSkKICBwbG90MiA9IFBBTV9zaWxob3VldHRlX3Zpel8zKFBBTSwgYW1wJG1ldGFkYXRhKSAKICAKICByZXR1cm4obGlzdChOTURTID0gcGxvdDEsIFBBTSA9IHBsb3QyLCBOTURTX3N0cmVzcyA9IE5NRFNfc3RyZXNzLCBQQU1fdmFsaWRhdGlvbiA9IFBBTV92YWxpZGF0aW9uKSkKICAKfQoKICByZXR1cm4ocGxvdDEpCn0KCgpOTURTX1BBTV9mdWxsID0gTk1EU19QQU0oZGF0YV9hbXAsIGphY2NhcmRfZnVsbCwgMiwgVFJVRSkKTk1EU19QQU1fZnVsbCRQQU1fdmFsaWRhdGlvbgoKTk1EU19QQU1fdGF4YSA9IE5NRFNfUEFNKGRhdGFfYW1wX3RheGEsIGphY2NhcmRfdGF4YSwgMiwgVFJVRSkKTk1EU19QQU1fdGF4YSRQQU1fdmFsaWRhdGlvbgoKTk1EU19QQU1fY29tYmluZWQgPSAoTk1EU19QQU1fZnVsbCROTURTICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIkEpIikpICsgCiAgKE5NRFNfUEFNX2Z1bGwkUEFNICArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJCKSIpKSArIAogIChOTURTX1BBTV90YXhhJE5NRFMgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2d0aXRsZSgiQykiKSkgKyAKICAoTk1EU19QQU1fdGF4YSRQQU0gKyBnZ3RpdGxlKCJEKSIpKSArIAogIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0Jywgd2lkdGhzID0gYygxLDEpKQoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTcuIgpzYXZlX3BkZl9wbmcocGxvdCA9IE5NRFNfUEFNX2NvbWJpbmVkLCBwYXRoID0gcGF0aCwgdyA9IDE2OSwgaCA9IDE2OSwgdSA9ICJtbSIsIGJnID0gInRyYW5zcGFyZW50IiwgZHBpID0gNjAwKQpgYGAKCkNvbW11bml0eSBjb21wb3NpdGlvbiBhbHNvIGRpZmZlcmVkIGFjcm9zcyBsb2NhdGlvbnMsIGFzIHN1cHBvcnRlZCBieSBtdWx0aXBsZSBhbmFseXNlcy4gVmFyaWF0aW9uIGluIGNvbW11bml0eSBjb21wb3NpdGlvbiB3YXMgc2lnbmlmaWNhbnRseSBleHBsYWluZWQgYnkgbG9jYXRpb24sIGV2ZW4gd2hlbiBhY2NvdW50aW5nIGZvciB2YXJpYXRpb24gZHVlIHRvIHRpbWUgb2Ygc2FtcGxpbmcgYW5kIHZhcmlhdGlvbiBiZXR3ZWVuIHJlcGxpY2F0ZXMgKEFTVnM6IFBFUk1BTk9WQSBwIFw8IDAuMDAxLCBiZXRhZGlzcGVyIHAgXD4gMC4wNTsgVGF4YTogUEVSTUFOT1ZBIHAgXDwgMC4wMDEsIGJldGFkaXNwZXIgcCBcPiAwLjA1KS4gQXMgdmlzdWFsaXplZCB1c2luZyBOTURTIG9yZGluYXRpb24sIFMxIGFuZCBTMiBzYW1wbGVzIGNvbGxlY3RlZCBhcm91bmQgbG93IHRpZGUgd2VyZSBtb3N0IGRpc3NpbWlsYXIgZnJvbSB0aGUgb2Zmc2hvcmUgc2FtcGxlcyAoRmlndXJlcyA3QSwgN0MpLiBUaGVzZSBwYXR0ZXJucyBwZXJzaXN0ZWQgaW4gdGhlIG9wdGltYWwgY2x1c3RlcnMgaWRlbnRpZmllZCB1c2luZyB0aGUgcGFydGl0aW9uaW5nIGFtb25nIG1lZG9pZHMgKFBBTSkgYWxnb3JpdGhtLCB3aXRob3V0IGFzc3VtaW5nIGEgcHJpb3JpIHRoYXQgbG9jYXRpb24gZHJpdmVzIHRoZSBjbHVzdGVycyAoRmlndXJlIDdCLCA3RCkuIFdoZW4gYW5hbHl6ZWQgYnkgQVNWLCBQQU0gaWRlbnRpZmllZCB0aHJlZSBvcHRpbWFsIGNsdXN0ZXJzLCBwcmltYXJpbHkgY29tcG9zZWQgb2Y6IDEpIG5lYXJzaG9yZSBzYW1wbGVzIHdpdGggYWRkaXRpb25hbCBzYW1wbGVzIGZyb20gUzEgYW5kIFMyIGF0IGVhcmx5IHRpbWUgcG9pbnRzLCAyKSB0aGUgcmVtYWluaW5nIFMxIHNhbXBsZXMsIGFuZCAzKSB0aGUgcmVtYWluaW5nIFMyIHNhbXBsZXMgKEZpZ3VyZSA3QikuIFdoZW4gYW5hbHl6aW5nIGJ5IHRheGEsIFBBTSBhZGRpdGlvbmFsbHkgZGlmZmVyZW50aWF0ZWQgYmV0d2VlbiBzYW1wbGVzIGZyb20gdGhlIHRocmVlIGxvY2F0aW9ucyBjb2xsZWN0ZWQgYXQgZWFybHkgdGltZSBwb2ludHMuIFRodXMsIG11bHRpcGxlIGFuYWx5c2VzIHdpdGggZGlmZmVyZW50IGluaXRpYWwgYXNzdW1wdGlvbnMgYWxsIGRlbW9uc3RyYXRlZCBkaWZmZXJlbnRpYWJsZSBlRE5BIHNpZ25hbHMgYWNyb3NzIG1pY3JvLWhhYml0YXRzLgoKPGNlbnRlcj4KCiFbKkZpZ3VyZSA3OiA6IE9yZGluYXRpb24gYW5hbHlzaXMgKE5NRFMgdXNpbmcgSmFjY2FyZCBEaXN0YW5jZTsgQSwgQykgYW5kIGNsdXN0ZXIgYW5hbHlzaXMgKHBhcnRpdGlvbmluZyBhbW9uZyBtZWRvaWRzIHdpdGggbnVtYmVyIG9mIGNsdXN0ZXJzIHZhbGlkYXRlZCB0byBtYXhpbWl6ZSBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGg7IEIsRCkuIFBhbmVscyBBICYgQiBhcmUgYW5hbHl6ZWQgYnkgQVNWLCBhbmQgcGFuZWxzIEMgJiBEIGFyZSBhbmFseXplZCBieSB0YXhhLiA5NSUgY29uZmlkZW5jZSBlbGxpcHNlcyBmb3IgdGhlIGNlbnRyb2lkcyBvZiBlYWNoIGxvY2F0aW9uIGJhc2VkIG9uIGEgbXVsdGl2YXJpYXRlIHQtZGlzdHJpYnV0aW9uIGFyZSBzaG93biBpbiB0aGUgTk1EUyBvcmRpbmF0aW9ucyB3aXRoIGJsYWNrIGRhc2hlZCBsaW5lcywgYW5kIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aCBpcyBzaG93biBpbiBjbHVzdGVyIGRpYWdyYW1zIHdpdGggYSByZWQgZGFzaGVkIGxpbmUuKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCmBgYHtyIEZpZ3VyZSA4fQoKZGlzdG1hdCA8LSBhcy5tYXRyaXgoamFjY2FyZF9mdWxsKQoKI0NhbGN1bGF0ZSBQYWlyd2lzZSBEaXNzaW1pbGFyaXR5IFZhbHVlcyBXaXRoaW4gYW5kIEFjcm9zcyBTaXRlcwoKSmFjY2FyZCA9IGMoKQpDb21ibyA9IGMoKQpUaW1lID0gYygpCnN1bW1hcnkgPSBkYXRhLmZyYW1lKEphY2NhcmQsIENvbWJvLCBUaW1lKQoKb25lID0gYygiUzEiLCAiUzIiLCAiTiIsICJTMSIsICJTMiIsICJTMSIpCm9uZV9uYW1lcyA9IGMoIlMxIiwgIlMyIiwgIk4iLCAiUzEiLCAiUzIiLCAiUzEiKQp0d28gPSBjKCJTMSIsICJTMiIsICJOIiwgIk4iLCAiTiIsICJTMiIpCnR3b19uYW1lcyA9IGMoIlMxIiwgIlMyIiwgIk4iLCAiTiIsICJOIiwgIlMyIikKCmZvcih4IGluIGxldmVscyhkYXRhX2FtcCRtZXRhZGF0YSRUaW1lKSl7CiAgc3Vic2V0ID0gZmlsdGVyKGRhdGFfYW1wJG1ldGFkYXRhLCBkYXRhX2FtcCRtZXRhZGF0YSRUaW1lID09IHgpCiAgCiAgZm9yKGkgaW4gMTogbGVuZ3RoKG9uZSkpIHsKICAgIG5hbWUgPSBwYXN0ZShvbmVfbmFtZXNbaV0sIHR3b19uYW1lc1tpXSwgc2VwID0gIjoiKQogICAgZGF0YSA9IGRpc3RtYXRbc3Vic2V0JFhbc3Vic2V0JExvY2F0aW9uID09IG9uZVtpXV0sIHN1YnNldCRYW3N1YnNldCRMb2NhdGlvbiA9PSB0d29baV1dXQogICAgSmFjY2FyZCA9IHZlY3RvcigpCiAgICAKICAgIGlmICghKDAgJWluJSBkaW0oZGF0YSkpKSB7CiAgICAgIGZvciAocm93IGluIDE6bnJvdyhkYXRhKSkgewogICAgICAgIGZvciAoY29sIGluIDE6bmNvbChkYXRhKSl7CiAgICAgICAgICAgaWYgKGNvbCA+IHJvdykgewogICAgICAgICAgICBKYWNjYXJkID0gYyhKYWNjYXJkLCBkYXRhW3Jvdyxjb2xdKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgQ29tYm8gPC0gcmVwKG5hbWUsIGxlbmd0aChKYWNjYXJkKSkKICAgIFRpbWUgPC0gcmVwKHgsIGxlbmd0aChKYWNjYXJkKSkKICAgIAogICAgc3VtbWFyeSA8LSByYmluZChzdW1tYXJ5LCBkYXRhLmZyYW1lKEphY2NhcmQsIENvbWJvLCBUaW1lKSkKICB9Cn0KCgojI1BMT1RUSU5HCgojRGVmaW5lIHBhbGV0dGUgZm9yIGNvbG9ycyBhbmQgZmlsbHMgCmNvbG9ycyA9IHR1cmJvKDgpCgpwYWxldHRlID0gYygiV2l0aGluIFNpdGUiID0gIiMzMDEyM0JGRiIsIAogICAgICAgICAgICAiUzE6TiIgPSIjMUFFNEI2RkYiICwgCiAgICAgICAgICAgICJTMjpOIiA9ICIjRkFCQTM5RkYiLCAKICAgICAgICAgICAgIlMxOlMyIiA9ICIjN0EwNDAzRkYiKQoKZmlsbF9wYWxldHRlID0gYygiV2l0aGluIFNpdGUiID0gIiMzMDEyM0IyMCIsIAogICAgICAgICAgICAgICAgICJTMTpOIiA9IiMxQUU0QjYyMCIsIAogICAgICAgICAgICAiUzI6TiIgPSAiI0ZBQkEzOTIwIiwgCiAgICAgICAgICAgICJTMTpTMiIgPSAiIzdBMDQwMzIwIikKCgojV0lUSElOIFNJVEUgQ09NQklORUQKCnN1bW1hcnkkQ29tYm8yIDwtIHN1bW1hcnkkQ29tYm8Kc3VtbWFyeSRDb21ibzJbc3VtbWFyeSRDb21ibzIgPT0gIlMxOlMxIl0gPSAiV2l0aGluIFNpdGUiCnN1bW1hcnkkQ29tYm8yW3N1bW1hcnkkQ29tYm8yID09ICJTMjpTMiJdID0gIldpdGhpbiBTaXRlIgpzdW1tYXJ5JENvbWJvMltzdW1tYXJ5JENvbWJvMiA9PSAiTjpOIl0gPSAiV2l0aGluIFNpdGUiCgpzdGF0cyA9IHN1bW1hcnkgJT4lIGZpbHRlcihDb21ibzIgPT0gIldpdGhpbiBTaXRlIikgJT4lIHN1bW1hcml6ZShtZWFuID0gbWVhbihKYWNjYXJkKSwgbWF4ID0gbWF4KEphY2NhcmQpKQoKCmcyLjUgPSBnZ3Bsb3Qoc3VtbWFyeSwgYWVzKHggPSBUaW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEphY2NhcmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGZhY3RvcihDb21ibzIsIGxldmVsID0gYygiV2l0aGluIFNpdGUiLCAiUzE6TiIsICJTMjpOIiwgIlMxOlMyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihDb21ibzIsIGxldmVsID0gYygiV2l0aGluIFNpdGUiLCAiUzE6TiIsICJTMjpOIiwgIlMxOlMyIikpKSkgKyAKICBnZW9tX2JveHBsb3QocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguNSwgcHJlc2VydmUgPSAic2luZ2xlIikpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGRvZGdlLndpZHRoID0gLjUpLCBhbHBoYT0wLjIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsIG5hbWUgPSAiU2l0ZSBQYWlyaW5ncyIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZmlsbF9wYWxldHRlLCBuYW1lID0gIlNpdGUgUGFpcmluZ3MiKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHN0YXRzJG1lYW4sIGNvbG9yID0gcGFsZXR0ZVsiV2l0aGluIFNpdGUiXSApICsgCiAgeWxhYigiSmFjY2FyZCBEaXNzaW1pbGFyaXR5IikgKwogIGNvb3JkX2NhcnRlc2lhbihleHBhbmQgPSAwLCBjbGlwID0gIm9mZiIpICsgCiAgZ2VvbV90ZXh0KGFlcyhtYXgoVGltZSksCiAgICAgICAgICAgICAgICBzdGF0cyRtZWFuLCAKICAgICAgICAgICAgICAgIGxhYmVsID0gIk1lYW4gRGlzc2ltaWxhcml0eVxuICBXaXRoaW4gU2l0ZXMiLCAKICAgICAgICAgICAgICAgIGhqdXN0ID0gLS4yKSwgCiAgICAgICAgICAgIGNvbG9yID0gcGFsZXR0ZVsiV2l0aGluIFNpdGUiXSwgCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsIAogICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTIpICsgCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiLGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJ0b3AiKQoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTguIgpzYXZlX3BkZl9wbmcocGxvdCA9IGcyLjUsIHBhdGggPSBwYXRoLCB3ID0gMTY5LCBoID0gMTIwLCB1ID0gIm1tIiwgYmcgPSAidHJhbnNwYXJlbnQiLCBkcGkgPSA2MDApCmBgYAoKVGhlIGV4dGVudCBvZiB0aGUgSmFjY2FyZCBkaXNzaW1pbGFyaXR5IGJldHdlZW4gc2FtcGxlcyBmcm9tIGRpZmZlcmVudCBsb2NhdGlvbnMgdmFyaWVkIG92ZXIgdGltZS4gQXMgc2hvd24gaW4gRmlndXJlIDgsIGV4Y2VwdCBhdCB0aGUgZmlyc3QgdGltZSBwb2ludCBzYW1wbGVkLCB0aGUgZGlzc2ltaWxhcml0eSBiZXR3ZWVuIHNhbXBsZXMgYWNyb3NzIHNpdGVzIHdhcyBhbHdheXMgZ3JlYXRlciB0aGFuIHRoZSBtZWFuIGRpc3NpbWlsYXJpdHkgYmV0d2VlbiBzYW1wbGVzIHdpdGhpbiB0aGUgc2FtZSBzaXRlLCBhbmQgaW5jcmVhc2luZ2x5IHNvIGFjcm9zcyB0aGUgcGVyaW9kIHNhbXBsZWQuIEF0IHR3byB0aW1lIHBvaW50cy0tLTE1OjMwIGFuZCAxNjowMC0tLWFmdGVyIGxvdyB0aWRlIGJ1dCBiZWZvcmUgd2F0ZXIgd2FzIG1vdmluZyBiZXR3ZWVuIGFsbCBsb2NhdGlvbnMgYWdhaW4sIGFsbCBkaXNzaW1pbGFyaXR5IHZhbHVlcyBhY3Jvc3Mgc2l0ZXMgd2VyZSBncmVhdGVyIHRoYW4gdGhlIG1heGltdW0gZGlzc2ltaWxhcml0eSByZWNvcmRlZCBiZXR3ZWVuIHR3byBzYW1wbGVzIGZyb20gdGhlIHNhbWUgc2l0ZS4KCjxjZW50ZXI+CgohWypGaWd1cmUgODogQm94IHBsb3RzIG92ZXIgdGltZSBzaG93aW5nIHRoZSBwYWlyd2lzZSBKYWNjYXJkIGRpc3NpbWlsYXJpdHkgdmFsdWVzIGJldHdlZW4gYWxsIHVuaXF1ZSBwYWlycyBvZiByZXBsaWNhdGVzIGZyb20gdGhlIHNhbWUgc2l0ZXMgKFdpdGhpbiBTaXRlKSBhbmQgYWxsIHVuaXF1ZSBwYWlycyBvZiBzYW1wbGVzIGFjcm9zcyB0d28gc2l0ZXMgKFMxOk8sIFM6TywgUzE6UzIpLiBUaGUgc29saWQgbGluZSBkZXBpY3RzIHRoZSBtZWFuIEphY2NhcmQgZGlzc2ltaWxhcml0eSB2YWx1ZSBmcm9tIHdpdGhpbiBzaXRlIHBhaXJpbmdzLipdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgojIyMjIDMuNC4gRWNvbG9naWNhbCBTaWduaWZpY2FuY2UKCmBgYHtyIEVjb2xvZ2ljYWwgU2lnbmlmaWNhbmNlLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQojIyNFY29sb2dpY2FsIFNpZ25pZmljYW5jZSMjIwoKI05PVCBET05FIFlFVCAKClMxX3VuaXF1ZSA9IHNldGRpZmYoUzFfdGF4YSwgdW5pb24oUzJfdGF4YSxOX3RheGEpICkgClMyX3VuaXF1ZSA9IHNldGRpZmYoUzJfdGF4YSwgdW5pb24oUzFfdGF4YSxOX3RheGEpICkgCk5fdW5pcXVlID0gc2V0ZGlmZihOX3RheGEsIHVuaW9uKFMyX3RheGEsUzFfdGF4YSkgKSAKCgpTMSA9IGRhdGEuZnJhbWUobGlzdChTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKFMxX3VuaXF1ZSksIFVuaXF1ZSA9ICJTMSIpKQpTMiA9IGRhdGEuZnJhbWUobGlzdChTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKFMyX3VuaXF1ZSksIFVuaXF1ZSA9ICJTMiIpKQpOID0gZGF0YS5mcmFtZShsaXN0KFNwZWNpZXMgPSByZW1vdmVfTkNCSW51bXMoTl91bmlxdWUpLCBVbmlxdWUgPSAiTiIpKQp1bmlxdWUgPSByYmluZChTMSwgUzIsIE4pCgpTMV9pID0gZGF0YS5mcmFtZShsaXN0KFNwZWNpZXMgPSByZW1vdmVfTkNCSW51bXMoZGF0YV9hbXAkdGF4JFNwZWNpZXNbcm93bmFtZXMoZGF0YV9hbXAkdGF4KSAlaW4lIGhlYXRtYXBfdGF4YSR0b3BfUzFdKSwgSW5kaWNhdG9yID0gIlMxIikpClMyX2kgPSBkYXRhLmZyYW1lKGxpc3QoU3BlY2llcyA9IHJlbW92ZV9OQ0JJbnVtcyhkYXRhX2FtcCR0YXgkU3BlY2llc1tyb3duYW1lcyhkYXRhX2FtcCR0YXgpICVpbiUgaGVhdG1hcF90YXhhJHRvcF9TMl0pLCBJbmRpY2F0b3IgPSAiUzIiKSkgICAgICAgICAgCk5faSA9IGRhdGEuZnJhbWUobGlzdChTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKGRhdGFfYW1wJHRheCRTcGVjaWVzW3Jvd25hbWVzKGRhdGFfYW1wJHRheCkgJWluJSBoZWF0bWFwX3RheGEkdG9wX05dKSwgSW5kaWNhdG9yID0gIk4iKSkgCmluZGljYXRvcnMgPSByYmluZChTMV9pLCBTMl9pLCBOX2kpCgpkZl9saXN0ID0gbGlzdCh1bmlxdWUsIGluZGljYXRvcnMpCmZ1bGxfdGF4YV9saXN0ID0gZGZfbGlzdCAlPiUgcmVkdWNlKGZ1bGxfam9pbiwgYnk9J1NwZWNpZXMnKQoKCgoKCnN5bm9ueW1zID0gYygpCmZvciAocyBpbiBmdWxsX3RheGFfbGlzdCRTcGVjaWVzKSB7CiAgcHJpbnQocykKICB3b3Jtc19JRCA9IGdldF93b3Jtc2lkKHMpCiAgaWYoaXMubmEod29ybXNfSUQpKSB7CiAgICBzeW5zID0gTkEKICB9IGVsc2UgewogICAgc3lucyA9IHN5bm9ueW1zKHdvcm1zX0lELCBkYiA9ICd3b3JtcycpCiAgICBzeW5zID0gdG9TdHJpbmcoc3luc1tbMV1dJHNjaWVudGlmaWNuYW1lKQogIH0KICBzeW5vbnltcyA9IHJiaW5kKHN5bm9ueW1zLCBzeW5zKQp9CgoKZnVsbF90YXhhX2xpc3QgPSBjYmluZChmdWxsX3RheGFfbGlzdCwgc3lub255bXMpCgojUmVtb3ZlIGFueXRoaW5nIGluIHBhcmVudGhldGljYWxzIApmdWxsX3RheGFfbGlzdCRzeW5vbnltcyA8LSBnc3ViKCJcXHMqXFwoW15cXCldK1xcKSIsICIiLCBmdWxsX3RheGFfbGlzdCRzeW5vbnltcykKCiNSZW1vdmUgYW55dGhpbmcgYmV5b25kIHR3byB3b3JkcyBpbiBlYWNoIGNvbW1hIHNlcGFyYXRlZCBzZWN0aW9uCmZvcihzeW4gaW4gMTpsZW5ndGgoZnVsbF90YXhhX2xpc3Qkc3lub255bXMpKSB7CiAgcHJpbnQoc3luKQogIGFsbCA9IHVubGlzdChzdHJzcGxpdChmdWxsX3RheGFfbGlzdCRzeW5vbnltc1tzeW5dLCAiLCIpKQogIGlmKCFpcy5uYShhbGxbMV0pKSB7CiAgICBwcmludChhbGwpCiAgICBmb3IoaSBpbiAxOmxlbmd0aChhbGwpKSB7CiAgICAgIHByaW50KGFsbFtpXSkKICAgICAgYWxsW2ldID0gc3RyX3RyaW0oYWxsW2ldKQogICAgICBhbGxbaV0gPC0gc3ViKCJeKFxcUypcXHMrXFxTKykuKiIsICJcXDEiLCBhbGxbaV0pCiAgICAgIHByaW50KGFsbFtpXSkKICAgIH0KICB9CiAgc3lucyA9IHRvU3RyaW5nKHVuaXF1ZShhbGwpKQogIGZ1bGxfdGF4YV9saXN0JHN5bm9ueW1zW3N5bl0gPSBzeW5zCn0KCgp3cml0ZS5jc3YoZnVsbF90YXhhX2xpc3QsICJBbmFseXNpcyBQcm9kdWN0cy9CUFRfQW5hbHlzaXMuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQoKCiNSZWFkIGluIG5lZWRlZCB0ZXh0IG9mIEJldHdlZW4gUGFjaWZpYyBUaWRlcyAoZmlsZSBub3QgZ2l2ZW4gb24gR2l0SHViIGR1ZSB0byBjb3B5cmlnaHQpCnR4dCA8LXBkZl90ZXh0KCJEYXRhL0JldHdlZW5QYWNpZmljVGlkZXNfVGV4dEZvclNlYXJjaGluZy5wZGYiKQp0b2MgPC1wZGZfdGV4dCgiRGF0YS9CZXR3ZWVuUGFjaWZpY1RpZGVzX1RPQy5wZGYiKQoKI2ZpcnN0IHJlbW92ZSBoeXBoZW5hdGVkIHNpdHVhdGlvbnMgIi1cbiIKI3RoZW4gcmVtb3ZlIGFsbCBsaW5lIGJyZWFrcyAiXG4iCnR4dCA9IGdzdWIoJy1cbicsICcnLCB0eHQpCnR4dCA9IGdzdWIoJ1xuJywgJyAnLCB0eHQpCgojQ2xlYW4gdXAgVE9DCnRvYyA9IHN0cnNwbGl0KHRvYywgIlxuIikKdG9jID0gYyh0b2NbWzFdXSwgdG9jW1syXV0sIHRvY1tbM11dKQpwYWdlX251bXMgPSBncmVwbCgiWzEyMzQ1Njc4OTAsXSQiLCB0b2MpCnRvYyA9IHRvY1twYWdlX251bXNdCgojRml4IHRoZSBjb3VwbGUgb2Ygc3RyaW5ncyB0aGF0IGFyZSBzcGxpdCBvdmVyIG11bHRpcGxlIGxpbmVzCnRvY19jbGVhbmVkID0gYyh0b2NbMToxNF0sIHBhc3RlMCh0b2NbMTVdLCB0b2NbMTZdKSwgdG9jWzE3OjIxXSwgcGFzdGUwKHRvY1syMl0sIHRvY1syM10pLCB0b2NbMjQ6NTNdKQp0b2NfY2xlYW5lZCA9IGFzLmRhdGEuZnJhbWUodG9jX2NsZWFuZWQpCnRvY19jbGVhbmVkID0gZXh0cmFjdCh0b2NfY2xlYW5lZCwgdG9jX2NsZWFuZWQsIGludG8gPSBjKCd0ZXh0JywgJ3BhZ2UnKSwgJyguKilcXHMrKFteIF0rKSQnKQp0b2NfY2xlYW5lZCRwYWdlID0gYXMubnVtZXJpYyh0b2NfY2xlYW5lZCRwYWdlKQoKCnRvY19jbGVhbmVkX21heCA9IHZlY3RvcigpCmZvcih4IGluIDE6KG5yb3codG9jX2NsZWFuZWQpLTEpKSB7CiAgcHJpbnQoeCkKICBpZiAodG9jX2NsZWFuZWQkcGFnZVt4XSA9PSB0b2NfY2xlYW5lZCRwYWdlW3grMV0pIHsKICAgIHRvY19jbGVhbmVkX21heFt4XSA9IHRvY19jbGVhbmVkJHBhZ2VbeF0KICB9IGVsc2UgewogICAgdG9jX2NsZWFuZWRfbWF4W3hdID0gdG9jX2NsZWFuZWQkcGFnZVt4KzFdLTEKICB9Cn0KdG9jX2NsZWFuZWRfbWF4W25yb3codG9jX2NsZWFuZWQpXSA9IE5BCgp0b2NfY2xlYW5lZCRtYXhfcGFnZSA9IHRvY19jbGVhbmVkX21heAoKI3JlbW92ZSBldmVyeXRoaW5nIG5vdCByZWZlcnJpbmcgdG8gcm9ja3kgc2hvcmVzCnRvY19jbGVhbmVkID0gdG9jX2NsZWFuZWRbMToxNyxdCgojUmVtb3ZlIGp1c3Qgcm93cyB3aXRoIHpvbmUKdG9jX3pvbmVzID0gdG9jX2NsZWFuZWQgJT4lIGZpbHRlcihncmVwbCgnWm9uZScsIHRleHQpKQp0b2Nfem9uZXMkdGV4dCA9IGdzdWIoIlxcLi4qIiwgIiIsIHRvY196b25lcyR0ZXh0KQp0b2Nfem9uZXMkdGV4dCA9IHRyaW13cyh0b2Nfem9uZXMkdGV4dCkKCgpvdXRwdXQgPSBjKCkKZm9yICh4IGluIDE6bGVuZ3RoKGZ1bGxfdGF4YV9saXN0JFNwZWNpZXMpKSB7CiAgc3BlY2llcyA9IGZ1bGxfdGF4YV9saXN0JFNwZWNpZXNbeF0KICBzeW5vbnltcyA9IGZ1bGxfdGF4YV9saXN0JHN5bm9ueW1zW3hdCiAgc3lub255bXMgPSB1bmxpc3Qoc3Ryc3BsaXQoc3lub255bXMsICIsICIpKQogIGFsbCA9IGMoc3BlY2llcywgc3lub255bXMpCiAgYWxsX2FiYnJldmlhdGVkID0gc3ViKCJbYS16XSogIiwgIi4gIiwgYWxsKQogIGFsbF90b19zZWFyY2ggPSBjKGFsbCwgYWxsX2FiYnJldmlhdGVkKQogIAogIGFsbF9wYWdlcyA9IHZlY3RvcigpCiAgZm9yKHkgaW4gYWxsX3RvX3NlYXJjaCkgewogICAgcHJpbnQoeSkKICAgIHBhZ2VzID0gZ3JlcCh5LCB0eHQsIGlnbm9yZS5jYXNlID0gRkFMU0UsIGZpeGVkID0gVFJVRSkKICAgIGFsbF9wYWdlcyA9IGMoYWxsX3BhZ2VzLCBwYWdlcykKICAgIHByaW50KHBhZ2VzKQogIH0KICBhbGxfcGFnZXMgPSB1bmlxdWUoYWxsX3BhZ2VzKQogIG91dHB1dFt4XSA9IGxpc3QoYWxsX3BhZ2VzKQp9CgpmdWxsX3RheGFfbGlzdCRwYWdlcyA9IG91dHB1dApmdWxsX3RheGFfbGlzdCRwYWdlc1tzYXBwbHkoZnVsbF90YXhhX2xpc3QkcGFnZXMsIGZ1bmN0aW9uKHgpIGxlbmd0aCh4KT09MCldIDwtIE5BCgoKCnpvbmVzID0gdW5pcXVlKHRvY196b25lcyR0ZXh0KQpkZiA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSBsZW5ndGgoem9uZXMpLCBucm93ID0gMCkpCmNvbG5hbWVzKGRmKSA9IHpvbmVzCgpuYW1lID0gYygpCnpvbmUgPSBjKCkKcGFnZSA9IGMoKQoKZm9yKHggaW4gMTpsZW5ndGgoZnVsbF90YXhhX2xpc3QkcGFnZXMpKSB7CiAgCiAgbGlzdCA9IGZ1bGxfdGF4YV9saXN0JHBhZ2VzW1t4XV0KICBpZighaXMubmEobGlzdFsxXSkpIHsKICAgIGZvcih5IGluIDE6bGVuZ3RoKGxpc3QpKSB7CiAgICBudW0gPSBsaXN0W3ldCiAgICBmb3IoeiBpbiAxOmxlbmd0aCh0b2Nfem9uZXMkdGV4dCkpIHsKICAgICAgbWluID0gdG9jX3pvbmVzJHBhZ2Vbel0KICAgICAgbWF4ID0gdG9jX3pvbmVzJG1heFt6XQogICAgICBpZiAobnVtIDw9IG1heCAmJiBudW0gPj0gbWluKSB7CiAgICAgICAgbmFtZSA9IGFwcGVuZChuYW1lLCBmdWxsX3RheGFfbGlzdCRTcGVjaWVzW3hdKQogICAgICAgIHpvbmUgPSBhcHBlbmQoem9uZSwgdG9jX3pvbmVzJHRleHRbel0pCiAgICAgICAgcGFnZSA9IGFwcGVuZChwYWdlLCBudW0pCiAgICAgIH0gZWxzZSB7CiAgICAgIH0KICAgIH0KICB9CiAgfQogIAp9CgpmaW5hbF8xID0gYXMuZGF0YS5mcmFtZShjYmluZChuYW1lLCB6b25lLCBwYWdlKSkKCiNTcGxpdCAiWm9uZXMgMSBhbmQgMiIgaW50byB0d28gZW50cmllcwp0b19zcGxpdCA9IGZpbmFsXzEgJT4lIGZpbHRlcih6b25lID09ICJab25lcyAxIGFuZCAyIikgJT4lIG11dGF0ZSh6b25lID0gIlpvbmUgMSIpCmZpbmFsXzIgPSBmaW5hbF8xICU+JSBtdXRhdGUoem9uZSA9IHJlcGxhY2Uoem9uZSwgem9uZSA9PSAiWm9uZXMgMSBhbmQgMiIsICJab25lIDIiKSkKZmluYWxfMiA9IHJiaW5kKGZpbmFsXzIsIHRvX3NwbGl0KQoKCiNTcGxpdCAiWm9uZXMgMiBhbmQgMyIgaW50byB0d28gZW50cmllcwp0b19zcGxpdCA9IGZpbmFsXzEgJT4lIGZpbHRlcih6b25lID09ICJab25lcyAyIGFuZCAzIikgJT4lIG11dGF0ZSh6b25lID0gIlpvbmUgMiIpCmZpbmFsXzIgPSBmaW5hbF8yICU+JSBtdXRhdGUoem9uZSA9IHJlcGxhY2Uoem9uZSwgem9uZSA9PSAiWm9uZXMgMiBhbmQgMyIsICJab25lIDMiKSkKZmluYWxfMiA9IHJiaW5kKGZpbmFsXzIsIHRvX3NwbGl0KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApjb25kZW5zZSA9IGZpbmFsXzIgJT4lIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB6b25lLCB2YWx1ZXNfZnJvbSA9IHBhZ2UsIHZhbHVlc19mbiA9IHVuaXF1ZShsaXN0KCkpKQoKCmNvbmRlbnNlID0gbGVmdF9qb2luKGNvbmRlbnNlLCBmdWxsX3RheGFfbGlzdFssYygiU3BlY2llcyIsICJVbmlxdWUiLCAiSW5kaWNhdG9yIildLCBieSA9IGpvaW5fYnkobmFtZSA9PSBTcGVjaWVzKSkKCmNvbmRlbnNlID0gY29uZGVuc2UgJT4lIG11dGF0ZShTaXRlID0gY29hbGVzY2UoVW5pcXVlLCBJbmRpY2F0b3IpKQpjb25kZW5zZSA9IGNvbmRlbnNlICU+JSByZWxvY2F0ZShTaXRlLCBVbmlxdWUsIEluZGljYXRvciwgbmFtZSwgJ1pvbmUgNCcsICdab25lIDMnLCAnWm9uZSAyJywgJ1pvbmUgMScpCgpjb25kZW5zZSA9IGNvbmRlbnNlICU+JSByZW5hbWUoWm9uZV8xID0gJ1pvbmUgMScsIFpvbmVfMiA9ICdab25lIDInLCAgWm9uZV8zID0gJ1pvbmUgMycsIFpvbmVfNCA9ICdab25lIDQnKQoKCgpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlIApjb25kZW5zZV9ub19wYWdlcyRab25lXzEgPSAhc2FwcGx5KGNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfMSwgaXMubnVsbCkKY29uZGVuc2Vfbm9fcGFnZXMkWm9uZV8yID0gIXNhcHBseShjb25kZW5zZV9ub19wYWdlcyRab25lXzIsIGlzLm51bGwpCmNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfMyA9ICFzYXBwbHkoY29uZGVuc2Vfbm9fcGFnZXMkWm9uZV8zLCBpcy5udWxsKQpjb25kZW5zZV9ub19wYWdlcyRab25lXzQgPSAhc2FwcGx5KGNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfNCwgaXMubnVsbCkKCgojQWRqdXN0IEJhc2VkIG9uIE1hbnVhbCBDaGVja2luZwoKI3JlbW92ZSAiUHJvYm9zY2lkYWN0eWxhIGZsYXZpY2lycmF0YSIgYmVjYXVzZSBzZWFyY2ggaWRlbnRpZmllZCB0aGUgd3JvbmcgYWJicmV2aWF0ZWQgc3lub255bQpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlX25vX3BhZ2VzICU+JSBmaWx0ZXIobmFtZSAhPSAiUHJvYm9zY2lkYWN0eWxhIGZsYXZpY2lycmF0YSIpCgojYWRkICJMYW1pbmFyaWEgc2V0Y2hlbGxpaSIgYmVjYXVzZSBpdCB3YXMgZm91bmQgbWFudWFsbHkgYW5kIG9ubHkgYXBwZWFycyBpbiBhIGRpYWdyYW0gKHNvIG5vdCBpbiB0ZXh0IHNlYXJjaCkKY29uZGVuc2Vfbm9fcGFnZXMgPSBjb25kZW5zZV9ub19wYWdlcyAlPiUgYWRkX3JvdyhTaXRlID0gIk4iLCBVbmlxdWUgPSAiTiIsIEluZGljYXRvciA9IE5BLCBuYW1lID0gIkxhbWluYXJpYSBzZXRjaGVsbGlpIiwgWm9uZV80ID0gVFJVRSwgWm9uZV8zID0gRkFMU0UsIFpvbmVfMiA9IEZBTFNFLCBab25lXzEgPSBGQUxTRSkKCiNhZGQgIkVncmVnaWEgbWVuemllc2lpIiBiZWNhdXNlIGl0IHdhcyBmb3VuZCBtYW51YWxseSB0aHJvdWdoIHRoZSBpbmRleCwgYnV0IG9ubHkgYXBwZWFycyBieSBnZW51cyBpbiB0aGUgdGV4dApjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlX25vX3BhZ2VzICU+JSBhZGRfcm93KFNpdGUgPSAiUzIiLCBVbmlxdWUgPSAiUzIiLCBJbmRpY2F0b3IgPSBOQSwgbmFtZSA9ICJFZ3JlZ2lhIG1lbnppZXNpaSIsIFpvbmVfNCA9IFRSVUUsIFpvbmVfMyA9IFRSVUUsIFpvbmVfMiA9IFRSVUUsIFpvbmVfMSA9IEZBTFNFKQoKI2FkZCAiUGFuZGFsdXMgZGFuYWUiIGJlY2F1c2UgaXQgd2FzIGZvdW5kIG1hbnVhbGx5IHRocm91Z2ggdGhlIGluZGV4LCBidXQgb25seSBhcHBlYXJzIGJ5IGdlbnVzIGluIHRoZSB0ZXh0CmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIGFkZF9yb3coU2l0ZSA9ICJTMiIsIFVuaXF1ZSA9ICJTMiIsIEluZGljYXRvciA9IE5BLCBuYW1lID0gIlBhbmRhbHVzIGRhbmFlIiwgWm9uZV80ID0gVFJVRSwgWm9uZV8zID0gRkFMU0UsIFpvbmVfMiA9IEZBTFNFLCBab25lXzEgPSBGQUxTRSkKCiNBZGp1c3QgIkVjdG9wbGV1cmEgbWFyaW5hIiB0byBpbmNsdWRlIFpvbmVfMyAoZm91bmQgbWFudWFsbHkgYmVjYXVzZSBtZW50aW9uZWQgb24gdGhhdCBwYWdlIHdpdGggZ2VudXMgb25seSwgYnV0IGxpbmtlZCBpbiB0aGUgaW5kZXgpCmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIG11dGF0ZShab25lXzMgPSByZXBsYWNlKFpvbmVfMywgbmFtZSA9PSAiRWN0b3BsZXVyYSBtYXJpbmEiLCBUUlVFKSkKCiNBZGp1c3QgIkhhbG9zeWRuYSBicmV2aXNldG9zYSIgdG8gaW5jbHVkZSBab25lXzQgKGZvdW5kIG1hbnVhbGx5IGJlY2F1c2UgbWVudGlvbmVkIG9uIHRoYXQgcGFnZSB3aXRoIGdlbnVzIG9ubHksIGJ1dCBsaW5rZWQgaW4gdGhlIGluZGV4KQpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlX25vX3BhZ2VzICU+JSBtdXRhdGUoWm9uZV80ID0gcmVwbGFjZShab25lXzQsIG5hbWUgPT0gIkhhbG9zeWRuYSBicmV2aXNldG9zYSIsIFRSVUUpKQoKCgpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlX25vX3BhZ2VzICU+JSBhcnJhbmdlKG5hbWUpCmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIGFycmFuZ2UoZGVzYyhab25lXzEpLCBkZXNjKFpvbmVfMiksIGRlc2MoWm9uZV8zKSwgZGVzYyhab25lXzQpKSAKY29uZGVuc2Vfbm9fcGFnZXMgPSBjb25kZW5zZV9ub19wYWdlcyAlPiUgYXJyYW5nZShmYWN0b3IoU2l0ZSwgbGV2ZWxzID0gYygiUzEiLCAiUzIiLCAiTiIpKSkKCgoKCgoKCmNvbnRpbmdlbmN5X3RhYmxlID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIGdyb3VwX2J5KFNpdGUpICU+JSBzdW1tYXJpc2UoSGlnaCA9IHN1bShab25lXzEgPT0gVFJVRSB8IFpvbmVfMiA9PSBUUlVFIHwgWm9uZV8zID09IFRSVUUpLCBMb3cgPSBzdW0oWm9uZV8xID09IEZBTFNFICYgWm9uZV8yID09IEZBTFNFICYgWm9uZV8zID09IEZBTFNFKSkKY29udGluZ2VuY3lfdGFibGUgPSBjb250aW5nZW5jeV90YWJsZSAlPiUgc2VsZWN0KC1TaXRlKSAlPiUgYXMubWF0cml4KCkKcm93bmFtZXMoY29udGluZ2VuY3lfdGFibGUpID0gYygiTiIsICJTMSIsICJTMiIpCgoKc2V0LnNlZWQoMSkKCnRlc3QgPSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlLCBjb3JyZWN0ID0gRkFMU0UsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFKQoKdGVzdF9wb3N0X2hvYyA9IGNoaXNxLnBvc3Rob2MudGVzdChjb250aW5nZW5jeV90YWJsZSwgbWV0aG9kID0gImJvbmZlcnJvbmkiLCBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSkKCgpmb3JfcGxvdHRpbmcgPSBjb25kZW5zZV9ub19wYWdlcwpmb3JfcGxvdHRpbmcgPSBmb3JfcGxvdHRpbmcgJT4lIG11dGF0ZShVbmlxdWUgPSByZXBsYWNlKFVuaXF1ZSwgIWlzLm5hKFVuaXF1ZSksICJYIiksIFVuaXF1ZSA9IHJlcGxhY2UoVW5pcXVlLCBpcy5uYShVbmlxdWUpLCAiIiksIEluZGljYXRvciA9IHJlcGxhY2UoSW5kaWNhdG9yLCAhaXMubmEoSW5kaWNhdG9yKSwgIlgiKSwgSW5kaWNhdG9yID0gcmVwbGFjZShJbmRpY2F0b3IsIGlzLm5hKEluZGljYXRvciksICIiKSkKCgoKCmZvcl9wbG90dGluZyA9IGZvcl9wbG90dGluZyAlPiUgCiAgZ3QoZ3JvdXBuYW1lX2NvbCA9ICJTaXRlIiwgaWQgPSAibXlndCIpICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiSW50ZXJ0aWRhbCBab25lcyIsCiAgICBjb2x1bW5zID0gYygKICAgICAgWm9uZV80LCBab25lXzMsIFpvbmVfMiwgWm9uZV8xCiAgICApCiAgKSAgJT4lCiAgdGFiX29wdGlvbnMocm93X2dyb3VwLmFzX2NvbHVtbiA9IFRSVUUpICAlPiUKICAgZ3RfY29sb3Jfcm93cygiWm9uZV80IiwgcGFsZXR0ZSA9IGMoIndoaXRlIiwgIiNEMUU3QzciKSkgJT4lCiAgZ3RfY29sb3Jfcm93cygiWm9uZV8zIiwgcGFsZXR0ZSA9IGMoIndoaXRlIiwgIiNCQkJFRDEiKSkgJT4lCiAgIGd0X2NvbG9yX3Jvd3MoIlpvbmVfMiIsIHBhbGV0dGUgPSBjKCJ3aGl0ZSIsICIjQkJCRUQxIikpICU+JQogIGd0X2NvbG9yX3Jvd3MoIlpvbmVfMSIsIHBhbGV0dGUgPSBjKCJ3aGl0ZSIsICIjQkJCRUQxIikpICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KHN0eWxlID0gIml0YWxpYyIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keSgKICAgICAgY29sdW1ucyA9IG5hbWUKICAgICkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KGNvbG9yID0gIiNGRkZGRkYwMCIsIHNpemUgPSAieC1zbWFsbCIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keSgKICAgICAgY29sdW1ucyA9IGMoIlpvbmVfNCIsICJab25lXzMiLCAiWm9uZV8yIiwgIlpvbmVfMSIpCiAgICApCikgJT4lIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KHNpemUgPSBweCgxMikpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keSgKICAgICAgY29sdW1ucyA9IGMoIlVuaXF1ZSIsICJJbmRpY2F0b3IiLCAibmFtZSIpCiAgICApCikgJT4lCiAgY29sc19hbGlnbigKICBhbGlnbiA9ICJjZW50ZXIiLAogIGNvbHVtbnMgPSBjKCJVbmlxdWUiLCAiSW5kaWNhdG9yIikKKSAlPiUKICBjb2xzX2xhYmVsKAogICAgWm9uZV8xID0gIjEiLAogICAgWm9uZV8yID0gIjIiLAogICAgWm9uZV8zID0gIjMiLAogICAgWm9uZV80ID0gIjQiLAogICAgbmFtZSA9ICJTcGVjaWVzIiwKICAgIFVuaXF1ZSA9ICJVbmlxLlxuVG8iLAogICAgSW5kaWNhdG9yID0gIkluZGljLlxuT2YiCiAgKSAlPiUKICB0YWJfc3R5bGUoCiAgc3R5bGUgPSAgY2VsbF90ZXh0KHZfYWxpZ24gPSAibWlkZGxlIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19yb3dfZ3JvdXBzKCkKICApICU+JSB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGNlbGxfYm9yZGVycygKICAgICAgc2lkZXMgPSBjKCJib3R0b20iKSwKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIHdlaWdodCA9IHB4KDMpCiAgICAKICAgICksCiAgICBsb2NhdGlvbnMgPSBsaXN0KGNlbGxzX2NvbHVtbl9zcGFubmVycygpLCBjZWxsc19jb2x1bW5fbGFiZWxzKCkpCiAgKSAlPiUgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX2JvcmRlcnMoCiAgICAgIHNpZGVzID0gImFsbCIsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICB3ZWlnaHQgPSBweCgzKQogICAgCiAgICApLAogICAgbG9jYXRpb25zID0gbGlzdChjZWxsc19yb3dfZ3JvdXBzKCkpCiAgKSAlPiUgCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX2JvcmRlcnMoCiAgICAgIHNpZGVzID0gImFsbCIsCiAgICBjb2xvciA9ICJibGFjayIKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KCkKICApICU+JSB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGNlbGxfYm9yZGVycygKICAgICAgc2lkZXMgPSAiYm90dG9tIiwKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIHdlaWdodCA9IHB4KDMpCiAgICAKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KHJvd3MgPSBjKDE4LCAzMSwgNDEpKQogICkgJT4lIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF9ib3JkZXJzKAogICAgICBzaWRlcyA9ICJyaWdodCIsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICB3ZWlnaHQgPSBweCgzKQogICAgCiAgICApLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gOCkKICApICU+JQoKICB0YWJfb3B0aW9ucyhkYXRhX3Jvdy5wYWRkaW5nID0gcHgoMSkpICU+JQogIGRhdGFfY29sb3IoCiAgICBjb2x1bW5zID0gVW5pcXVlLAogICAgcm93cyA9IFVuaXF1ZSA9PSAiWCIsCiAgICBwYWxldHRlID0gImxpZ2h0Z3JheSIsCiAgKSAlPiUKICBkYXRhX2NvbG9yKAogICAgY29sdW1ucyA9IEluZGljYXRvciwKICAgIHJvd3MgPSBJbmRpY2F0b3IgPT0gIlgiLAogICAgcGFsZXR0ZSA9ICJsaWdodGdyYXkiLAogICkgJT4lCiAgdGFiX29wdGlvbnMoCiAgICB0YWJsZS5ib3JkZXIudG9wLnN0eWxlID0gImhpZGRlbiIKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KGFsaWduID0gImNlbnRlciIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfY29sdW1uX2xhYmVscyhjb2x1bW5zID0gbmFtZSkpCgogCiAgCnBhdGggPSAiRmlndXJlcy9GaWd1cmU5LnBuZyIKZ3RzYXZlKGZvcl9wbG90dGluZywgZmlsZW5hbWUgPSBwYXRoKQoKCgoKCmBgYAoKSWRlbnRpZmllZCB1bmlxdWUgYW5kIGluZGljYXRvciB0YXhhIHJlZmxlY3RlZCBrbm93biBlY29sb2dpY2FsIGRpZmZlcmVuY2VzIGJldHdlZW4gbG9jYXRpb25zLiBPbmx5IGEgc3Vic2V0IG9mIHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHRheGEgd2VyZSBkZXNjcmliZWQgaW4gQmV0d2VlbiBQYWNpZmljIFRpZGVzOiAxOC44JSAoOS80OCkgb2YgbmVhcnNob3JlIHRheGEsIDMyLjElICgxNy81Mykgb2YgUzEgdGF4YSwgYW5kIDMxLjElICgxNC80NSkgb2YgUzIuIEhvd2V2ZXIsIGFjcm9zcyB0aGUgZGVzY3JpYmVkIHN1YnNldCwgbW9yZSB0YXhhIGZyb20gUzEgd2VyZSBjYXRlZ29yaXplZCB0byBoaWdoIGFuZCBtaWRkbGUgaW50ZXJ0aWRhbCB6b25lcyB0aGFuIFMyIGFuZCBOIChGaWd1cmUgOTsgbm90IG1hZGUgaW4gUikuIFRoZSBwcm9wb3J0aW9uIG9mIHRheGEgZnJvbSB0aGUgaGlnaCBhbmQgbWlkZGxlIGludGVydGlkYWwgdmFyaWVkIHNpZ25pZmljYW50bHkgYWNyb3NzIGxvY2F0aW9ucyAoz4cyID0xMS42NywgcFw8MC4wNSksIG1hdGNoaW5nIHRoZSBlbnZpcm9ubWVudGFsIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc2l0ZXMuCgo8Y2VudGVyPgoKIVsqRmlndXJlIDk6IENoYXJ0IGhhYml0YXQgaW5mb3JtYXRpb24gYWJvdXQgdW5pcXVlIGFuZCBpbmRpY2F0b3Igc3BlY2llcyBwcmVzZW50IGluIEJldHdlZW4gUGFjaWZpYyBUaWRlcypdKGByIHBhc3RlMChwYXRoKWApCgo8L2NlbnRlcj4KCiMjIyBTdXBwb3J0aW5nIEluZm9ybWF0aW9uCgpgYGB7ciBTdXBwb3J0aW5nIEZpZ3VyZSAxfQojIyNTdXBwb3J0aW5nIEZpZ3VyZSAxIyMjCgpwYXRoID0gIkZpZ3VyZXMvRmlndXJlUzEuIgpzYXZlX3BkZl9wbmcocGxvdCA9IGhlYXRtYXBfQVNWJHBsb3QsIHBhdGggPSBwYXRoLCB3ID0gMTY5LCBoID0gMzAwLCB1ID0gIm1tIiwgYmcgPSAidHJhbnNwYXJlbnQiLCBkcGkgPSA2MDApCmBgYAoKPGNlbnRlcj4KCiFbKkZpZ3VyZSBTMTogSGVhdCBtYXAgb2YgaWRlbnRpZmllZCBpbmRpY2F0b3IgQVNWcyBmb3IgYWxsIHRocmVlIGxvY2F0aW9ucyBvdmVyIHRpbWUsIHNjYWxlZCBieSB0aGUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMgdGhhdCBkZXRlY3RlZCB0aGF0IHNwZWNpZXMuKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCmBgYHtyIFN1cHBvcnRpbmcgVGFibGUgMX0KIyNTdXBwb3J0aW5nIFRhYmxlIDEjIyMKCm92ZXJsYXBfdGFibGUKd3JpdGUuY3N2KG92ZXJsYXBfdGFibGUsICJBbmFseXNpcyBQcm9kdWN0cy9UYWJsZVMxLmNzdiIsIHJvdy5uYW1lcz1GQUxTRSkKYGBgCgpCeSBhbmFseXppbmcgb2NjdXJyZW5jZSBkYXRhIGZyb20gdGhlIEdsb2JhbCBCaW9kaXZlcnNpdHkgSW5mb3JtYXRpb24gRmFjaWxpdHkgKG9uIGByIFN5cy5EYXRlKClgIGBTeXMuRGF0ZSgpYCksIHdlIGNvbmZpcm1lZCB0aGF0IGByIHBlcmNlbnRhZ2VzJGNvdW50WzZdYCBgcGVyY2VudGFnZXMkY291bnRbNl1gIG9mIGBgYCByIHN1bShwZXJjZW50YWdlcyRjb3VudClgYHN1bShwZXJjZW50YWdlcyRjb3VudCkgYGBgIGlkZW50aWZpZWQgc3BlY2llcyAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls2XSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzZdICogMTAwKWApIGhhdmUgb2NjdXJyZW5jZSByZWNvcmRzIGF0IFBpbGxhciBQb2ludCwgc3BlY2lmaWNhbGx5LiBBbiBhZGRpdGlvbmFsIGByIHBlcmNlbnRhZ2VzJGNvdW50WzVdYCBgcGVyY2VudGFnZXMkY291bnRbNV1gIGlkZW50aWZpZWQgc3BlY2llcyAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls1XSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzVdICogMTAwKWApIGhhdmUgb2NjdXJyZW5jZSByZWNvcmRzIGluIHRoZSBDYWxpZm9ybmlhIEN1cnJlbnQgU3lzdGVtIChDQ1MpIGFuZCBrbm93biByYW5nZXMgdGhhdCBlbmNvbXBhc3MgUGlsbGFyIFBvaW50LiBPZiB0aGUgcmVtYWluaW5nIHNwZWNpZXMsIHNvbWUgb25seSBmdWxmaWxsZWQgb25lIG9mIHR3byBjcml0ZXJpYTsgYHIgcGVyY2VudGFnZXMkY291bnRbNF1gIGBwZXJjZW50YWdlcyRjb3VudFs0XWAgaWRlbnRpZmllZCBzcGVjaWVzIChgciBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzRdICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbNF0gKiAxMDApYCkgaGFkIG9jY3VycmVuY2UgcmVjb3JkcyBpbiB0aGUgQ0NTIGJ1dCBrbm93biByYW5nZXMgdGhhdCBkaWQgbm90IGVuY29tcGFzcyBQaWxsYXIgUG9pbnQgYW5kIGByIHBlcmNlbnRhZ2VzJGNvdW50WzNdYCBgcGVyY2VudGFnZXMkY291bnRbM11gIGlkZW50aWZpZWQgc3BlY2llcyAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlclszXSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzNdICogMTAwKWApIGhhZCByYW5nZXMgdGhhdCBlbmNvbXBhc3MgUGlsbGFyIFBvaW50IGJ1dCBubyBvY2N1cnJlbmNlIHJlY29yZHMgaW4gdGhlIENDUy4gQWRkaXRpb25hbGx5LCBgciBwZXJjZW50YWdlcyRjb3VudFsxXWAgYHBlcmNlbnRhZ2VzJGNvdW50WzFdYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbMV0gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlclsxXSAqIDEwMClgKSBoYWQgbmVpdGhlciBvY2N1cnJlbmNlIHJlY29yZHMgaW4gdGhlIENDUyBub3Iga25vd24gcmFuZ2VzIHRoYXQgZW5jb21wYXNzZWQgUGlsbGFyIFBvaW50LiBGaW5hbGx5LCBgciBwZXJjZW50YWdlcyRjb3VudFsyXWAgYHBlcmNlbnRhZ2VzJGNvdW50WzJdYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbMl0gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlclsyXSAqIDEwMClgKSBsYWNrZWQgc3VmZmljaWVudCBvY2N1cnJlbmNlIHJlY29yZHMgaW4gR0JJRiB0byBtYWtlIGFueSBkZXNpZ25hdGlvbiwgYW5kIGByIHBlcmNlbnRhZ2VzJGNvdW50WzddYCBgcGVyY2VudGFnZXMkY291bnRbN11gIGlkZW50aWZpZWQgc3BlY2llcyAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls3XSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzddICogMTAwKWApIGRpZCBub3QgaGF2ZSBzcGVjaWVzLWxldmVsIHJlY29yZHMgaW4gR0JJRi4gRnVsbCBkZXRhaWxzIGJ5IHNwZWNpZXMgY2FuIGJlIGZvdW5kIGluIFRhYmxlIFMyLgoKYGBge3IgU3VwcG9ydGluZyBUYWJsZSAyfQojI1N1cHBvcnRpbmcgVGFibGUgMiMjIwoKR0JJRl9zdW1tYXJ5Cgp3cml0ZS5jc3YoR0JJRl9zdW1tYXJ5LCAiQW5hbHlzaXMgUHJvZHVjdHMvVGFibGVTMi5jc3YiLCByb3cubmFtZXM9VFJVRSkKYGBgCgojIyMgQ29kZSBmb3IgTWFraW5nIFZlcnNpb25zIG9mIEZpZ3VyZXMgZm9yIFBvd2VyUG9pbnQKCipGaWd1cmUgMyoKCmBgYHtyLCBGaWd1cmUgMyBGb3IgUG93ZXJwb2ludCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9CiMjI1ZlcnNpb24gb2YgRmlndXJlIDMgb3B0aW1pemVkIGZvciBQb3dlclBvaW50IHNsaWRlcy9hbmltYXRpb25zIyMjCgpncmFwaCA9IHNhbXBsZV9zY2hlbWEgCgppZiAoIWRpci5leGlzdHMoIkZpZ3VyZXMvUG93ZXJQb2ludCIpKSB7ZGlyLmNyZWF0ZSgiRmlndXJlcy9Qb3dlclBvaW50IiwgcmVjdXJzaXZlID0gVFJVRSl9CgpmaWxlbmFtZSA9IHBhc3RlMCgic2FtcGxlX3NjaGVtYV9mdWxsLnBkZiIpCiAgcGF0aCA9IHBhc3RlMCgiRmlndXJlcy9Qb3dlclBvaW50LyIsIGZpbGVuYW1lKQogIHBkZihwYXRoLCB3aWR0aCA9IDEzLCBoZWlnaHQgPSA0LjMpCiAgcHJpbnQoZ3JhcGgpCiAgZGV2Lm9mZigpCiAgCiAgZ3JhcGgkbGF5ZXJzW1sxXV0gPC0gTlVMTAogIAogIGFscGhhPWMoMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDApCiAKZm9yIChpIGluIDE6MTIpIHsKICBhbHBoYVtpXSA9IDEKICBncmFwaCA8LSBncmFwaCArIAogICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKGRpcmVjdGlvbiA9IC0xLCBhbHBoYSA9IGFscGhhKSArCiAgICAgc2NhbGVfZmlsbF92aXJpZGlzX2QoZGlyZWN0aW9uID0gLTEsIGFscGhhID0gYWxwaGEpCiAgZmlsZW5hbWUgPSBwYXN0ZTAoInNhbXBsZV9zY2hlbWEiLCBpLCAiLnBkZiIpCiAgcGF0aCA9IHBhc3RlMCgiRmlndXJlcy9Qb3dlclBvaW50LyIsIGZpbGVuYW1lKQogIHBkZihwYXRoLCB3aWR0aCA9IDEzLCBoZWlnaHQgPSA0LjMpCiAgcHJpbnQoZ3JhcGgpCiAgZGV2Lm9mZigpCn0KYGBgCgoqRmlndXJlIDQqCgpgYGB7ciwgRmlndXJlIDQgRm9yIFBvd2VycG9pbnQsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnfQojIyNWZXJzaW9uIG9mIEZpZ3VyZSA0IG9wdGltaXplZCBmb3IgUG93ZXJQb2ludCBzbGlkZXMvYW5pbWF0aW9ucyMjIwoKcCA8LSBnZ3RyZWU6OmdndHJlZShwdF9waHlzZXEsICBsYXlvdXQgPSAicmVjdGFuZ3VsYXIiKSAKCm9yZGVyZWRfbmFtZXMgPSBnZ3RyZWU6OmdldF90YXhhX25hbWUocCkKb3JkZXJlZF9uYW1lcyA9IHVuaXF1ZShvcmRlcmVkX25hbWVzKQpvcmRlcmVkX25hbWVzW21hdGNoKHJvd25hbWVzKHRheF90YWJsZShwdF9waHlzZXEpKSwgb3JkZXJlZF9uYW1lcyldID0gdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCJQaHlsdW0iXQpvcmRlcmVkX25hbWVzID0gdW5pcXVlKG9yZGVyZWRfbmFtZXMpCgpuYW1lcyhjb2xvcnNfb3JkZXJlZCkgPSBvcmRlcmVkX25hbWVzCgpwID0gcCArIGdlb21fZnJ1aXQoZ2VvbSA9IGdlb21fdGlsZSwgbWFwcGluZyA9IGFlcyhmaWxsID0gUGh5bHVtKSwgd2lkdGggPSAzLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSAgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnNfb3JkZXJlZCkgK3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnNfb3JkZXJlZCkKCnAgPSBwICsgZ2d0cmVlOjpnZW9tX2hpbGlnaHQoZGF0YT1waHlsYV9ub2RlcywgbWFwcGluZz1hZXMobm9kZSA9IG5vZGUsIGZpbGwgPSBub2RlX3BoeWx1bSksIHNob3cubGVnZW5kID0gRkFMU0UpCgpwID0gcCArCiAgdGhlbWUoCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnLCBjb2xvcj1OQSksCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksCiAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKQogICkKCmdnc2F2ZSgKICAiRmlndXJlcy9Qb3dlclBvaW50L3BoeWxvLnBkZiIsCiAgcGxvdCA9IHAsCiAgd2lkdGggPSA0LjQ5LAogIGhlaWdodCA9IDcuMDYsCiAgZHBpID0gMzAwLAogIGJnPSd0cmFuc3BhcmVudCcpCmBgYAoKKkZpZ3VyZSA2KgoKYGBge3IsIEZpZ3VyZSA2IEZvciBQb3dlcnBvaW50LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30KIyMjVmVyc2lvbiBvZiBGaWd1cmUgNiBvcHRpbWl6ZWQgZm9yIFBvd2VyUG9pbnQgc2xpZGVzL2FuaW1hdGlvbnMjIyMKCiBncmFwaCA9IGhlYXRtYXBfdGF4YSRwbG90IAoKICBwYXRoID0gIkZpZ3VyZXMvUG93ZXJQb2ludC9pbmRpY2F0b3JfZmlndXJlLnBuZyIKICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXRoLCBwbG90ID0gZ3JhcGgsIHdpZHRoID0gMTMsIGhlaWdodCA9IDYuNjkpCiAgCmBgYAoKKkZpZ3VyZSA3KgoKYGBge3IsIEZpZ3VyZSA3IEZvciBQb3dlcnBvaW50LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30KIyMjVmVyc2lvbiBvZiBGaWd1cmUgNyBvcHRpbWl6ZWQgZm9yIFBvd2VyUG9pbnQgc2xpZGVzL2FuaW1hdGlvbnMjIyMKCmFscGhhPWMoMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDApCmdyYXBoID0gTk1EU19QQU1fZnVsbCROTURTICsgCiAgZ2d0aXRsZSgiTk1EUyBPcmRpbmF0aW9uIChKYWNjYXJkIERpc3NpbWlsYXJpdHkpIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTgpCgpmaWxlbmFtZSA9IHBhc3RlKCJOTURTX2ZpZ3VyZV9mdWxsLnBkZiIpCiAgcGF0aCA9IHBhc3RlKCJGaWd1cmVzL1Bvd2VyUG9pbnQvIiwgZmlsZW5hbWUpCiAgcGRmKHBhdGgsIHdpZHRoID0gMTEuOTcsIGhlaWdodCA9IDYuMTQpCiAgcHJpbnQoZ3JhcGgpCiAgZGV2Lm9mZigpCiAgCiAgZ3JhcGgkbGF5ZXJzW1syXV0gPC0gTlVMTAogIAogIGdyYXBoID0gZ3JhcGggKyAKICAgIHN0YXRfZWxsaXBzZShhZXMoZ3JvdXA9TG9jYXRpb24pLCB0eXBlID0gInQiLGxpbmV0eXBlID0gMiwgYWxwaGEgPSAwKSAKICAKZm9yIChpIGluIDE6MTIpIHsKICBhbHBoYVtpXSA9IDEKICBncmFwaCA8LSBncmFwaCArIAogICAgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZT1UUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kID0gLjk3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gLTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhKSAKICBmaWxlbmFtZSA9IHBhc3RlKCJOTURTX2ZpZ3VyZSIsIGksICIucGRmIikKICBwYXRoID0gcGFzdGUoIkZpZ3VyZXMvUG93ZXJQb2ludC8iLCBmaWxlbmFtZSkKICBwZGYocGF0aCwgd2lkdGggPSAxMS45NywgaGVpZ2h0ID0gNi4xNCkKICBwcmludChncmFwaCkKICBkZXYub2ZmKCkKICBhbHBoYVtpXSA9IC4yCn0KYGBgCgojIyMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK